<template>
  <view class="container">
    <view class="header">
      <text class="title">直播页面</text>
    </view>
    
    <view class="main-content">
      <!-- 主画面区域 -->
      <view class="main-video-section">
        <text class="section-title">{{ liveTitle }}</text>
        <view class="main-video-wrapper">
          <!-- 本地视频预览 -->
          <view v-if="localStream" class="main-video-container">
            <view v-html="localVideoElement"></view>
          </view>
          
          <view v-if="!localStream" class="placeholder">
            <text v-if="status === 'pending'">正在获取媒体权限...</text>
            <text v-else-if="status === 'denied'">权限被拒绝，请手动开启摄像头和麦克风权限</text>
            <text v-else-if="status === 'error'">{{ errorMessage }}</text>
            <text v-else-if="status === 'stopped'">已停止推流</text>
            <text v-else>等待操作...</text>
          </view>
          
          <!-- 弹幕滚动区域 - 显示在主画面区域 -->
          <view class="danmaku-container" :class="{ 'fullscreen-danmaku': isFullscreen }">
            <view 
              v-for="(item, index) in scrollingDanmakuList" 
              :key="index" 
              class="danmaku-scroll-item" 
              :style="getDanmakuStyle(item, index)"
              v-show="!item.hidden"
              @animationend="handleDanmakuEnd(item)"
            >
              {{ item.user }}：{{ item.content }}
            </view>
          </view>
          
          <!-- 全屏控制按钮 -->
          <view class="fullscreen-controls">
            <button class="fullscreen-btn" @click="toggleFullscreen">
              {{ isFullscreen ? '退出全屏' : '全屏' }}
            </button>
          </view>
          
          <!-- 全屏弹幕输入区域 -->
          <view v-if="isFullscreen" class="fullscreen-danmaku-input">
            <input 
              class="fullscreen-message-input" 
              type="text" 
              v-model="inputMessage" 
              placeholder="发送弹幕..."
              @confirm="sendMessage"
              @keyup.enter="sendMessage"
            />
            <button class="fullscreen-send-btn" @click="sendMessage">发送</button>
          </view>
        </view>
      </view>
      
      <!-- 观众画面区域 -->
      <view class="audience-video-section">
        <text class="section-title">直播间观众数/应到人数 ({{ audienceCount }})</text>
        <view class="audience-video-wrapper">
          <!-- 观众视频播放区域 -->
          <view 
            v-for="stream in audienceStreams" 
            :key="stream.userId" 
            class="remote-video-container"
          >
            <!-- 有流时显示视频 -->
            <view v-if="stream.hasStream" class="video-container">
              <!-- 摄像头开启时显示视频 -->
              <view v-if="stream.cameraEnabled" v-html="getAudienceVideoElement(stream.userId)"></view>
              
              <!-- 摄像头关闭时显示占位符 -->
              <view v-else class="camera-disabled-placeholder">
                <div class="placeholder-icon">📹❌</div>
                <div class="placeholder-text">摄像头已关闭</div>
              </view>
              
              <!-- 视频上的状态标签 -->
              <text class="video-overlay-label" :class="getMonitoringStatusClass(stream)">
                {{ getDisplayName(stream) }}
              </text>
              
              <!-- 摄像头和麦克风控制按钮 -->
              <view class="device-controls">
                <button 
                  class="control-icon-btn camera-btn" 
                  :class="{ 'disabled': !stream.cameraEnabled }"
                  @click="toggleStudentCamera(stream.userId, stream.studentId)"
                  :title="stream.cameraEnabled ? '关闭摄像头' : '开启摄像头'"
                >
                  {{ stream.cameraEnabled ? '📹' : '📹❌' }}
                </button>
                <button 
                  class="control-icon-btn mic-btn" 
                  :class="{ 'disabled': !stream.micEnabled }"
                  @click="toggleStudentMicrophone(stream.userId, stream.studentId)"
                  :title="stream.micEnabled ? '关闭麦克风' : '开启麦克风'"
                >
                  {{ stream.micEnabled ? '🎤' : '🎤❌' }}
                </button>
              </view>
            </view>
            
            <!-- 无流时显示占位符 -->
            <view v-else class="audience-placeholder" :class="{ 'not-joined': !stream.hasStream }">
              <view class="placeholder-icon">👤</view>
              <text class="placeholder-text">
                {{ stream.isPlaceholder ? stream.studentName : '等待推流中...' }}
              </text>
              <text v-if="!stream.hasStream" class="not-joined-text">未加入直播</text>
            </view>
            
            <!-- 只在占位符状态下显示标签 -->
            <text v-if="!stream.hasStream" class="video-label remote-label offline-label">
              {{ getDisplayName(stream) }}
              <text class="status-indicator offline">未加入</text>
            </text>
            
            <!-- 摄像头控制按钮 -->
            <view class="camera-control-overlay">
              <button 
                class="camera-control-btn"
                :class="{ 'camera-disabled': getCameraStatus(stream.userId) === 'disabled' }"
                @click="toggleUserCamera(stream.userId)"
              >
                <text class="camera-icon">{{ getCameraStatus(stream.userId) === 'enabled' ? '📹' : '📷' }}</text>
                <text class="camera-text">{{ getCameraStatus(stream.userId) === 'enabled' ? '关闭' : '开启' }}</text>
              </button>
            </view>
          </view>
          
        </view>
      </view>
      
      <!-- 弹幕列表区域 -->
      <view class="danmaku-list-section">
        <text class="section-title">弹幕列表</text>
        <div class="danmaku-list-wrapper">
          <view 
            v-for="(item, index) in danmakuList" 
            :key="index" 
            class="danmaku-history-item"
            :style="{ borderLeftColor: item.color }"
          >
            <text v-if="item.user" class="danmaku-history-user">{{ item.user }}：</text>
            <text class="danmaku-history-content">{{ item.content }}</text>
            <text class="danmaku-history-time">{{ formatTime(item.timestamp) }}</text>
          </view>
          
          <!-- 当没有弹幕时显示占位符 -->
          <view v-if="danmakuList.length === 0" class="danmaku-placeholder">
            <text>暂无弹幕消息</text>
          </view>
        </div>
      </view>
    </view>

    <!-- 弹幕发送区域 -->
    <view class="danmaku-input-section" :class="{ 'fullscreen-input': isFullscreen }">
      <view class="input-area">
        <view class="danmaku-switch" @click="toggleDanmaku">
          <text class="switch-text">弹幕</text>
          <view class="switch-icon" :class="{ active: isDanmakuEnabled }"></view>
        </view>
        <input 
          class="message-input" 
          type="text" 
          v-model="inputMessage" 
          placeholder="说点什么..."
          @confirm="sendMessage"
          @keyup.enter="sendMessage"
          @keyup.13="sendMessage"
        />
        <button class="send-btn" @click="sendMessage">发送</button>
      </view>
    </view>
    
    <!-- 全屏时的弹幕输入区域 -->
    <view v-if="isFullscreen" class="fullscreen-danmaku-input">
      <view class="fullscreen-input-area">
        <button class="danmaku-toggle-btn" @click="toggleDanmaku" :class="{ active: isDanmakuEnabled }">
          {{ isDanmakuEnabled ? '弹幕开' : '弹幕关' }}
        </button>
        <input 
          class="fullscreen-message-input" 
          type="text" 
          v-model="inputMessage" 
          placeholder="发送弹幕..."
          @confirm="sendMessage"
          @keyup.enter="sendMessage"
          @keyup.13="sendMessage"
        />
        <button class="fullscreen-send-btn" @click="sendMessage">发送</button>
      </view>
    </view>

    <view class="controls">
      <button
        v-if="localStream"
        class="control-btn stop-btn"
        @click="stopStream"
      >
        停止推流
      </button>
      <button
        v-else
        class="control-btn start-btn"
        @click="startStream"
      >
        开始推流
      </button>
      
      <!-- 添加切换视频流按钮 -->
      <button
        v-if="localStream"
        class="control-btn switch-btn"
        @click="switchStream"
      >
        切换视频流
      </button>
      
      <!-- 添加推流按钮 -->
      <button
        v-if="localStream && !isPublishing"
        class="control-btn publish-btn"
        @click="startPublishing"
      >
        开始直播
      </button>
      <button
        v-else-if="localStream && isPublishing"
        class="control-btn stop-publish-btn"
        @click="stopPublishing"
      >
        停止直播
      </button>
      
      <!-- 测试弹幕按钮 -->
      <button class="control-btn test-btn" @click="testDanmaku">
        测试弹幕
      </button>
      
      <!-- 签到按钮 -->
      <button
        v-if="signalingConnection && roomId"
        class="control-btn attendance-btn"
        @click="startAttendance"
        :disabled="attendanceInProgress"
      >
        {{ attendanceInProgress ? '签到进行中...' : '发起签到' }}
      </button>
      
      <!-- 监控控制按钮 -->
      <button
        class="control-btn monitoring-btn"
        :class="{ 'active': monitoringEnabled }"
        @click="toggleMonitoring"
        :disabled="!isPublishing"
      >
        {{ monitoringEnabled ? '停止监控' : '开启监控' }}
      </button>
      
      <!-- 设备控制按钮 -->
      <button
        class="control-btn device-control-btn"
        @click="controlAllStudentsDevices('camera', false)"
        :disabled="!isPublishing"
      >
        关闭所有摄像头
      </button>
      <button
        class="control-btn device-control-btn"
        @click="controlAllStudentsDevices('camera', true)"
        :disabled="!isPublishing"
      >
        开启所有摄像头
      </button>
      <button
        class="control-btn device-control-btn"
        @click="controlAllStudentsDevices('microphone', false)"
        :disabled="!isPublishing"
      >
        关闭所有麦克风
      </button>
      <button
        class="control-btn device-control-btn"
        @click="controlAllStudentsDevices('microphone', true)"
        :disabled="!isPublishing"
      >
        开启所有麦克风
      </button>
    </view>

    <!-- 添加推流地址输入 -->
    <view class="publish-info">
      <input 
        class="publish-input" 
        v-model="publishUrl" 
        placeholder="请输入信令服务器地址，例如：http://localhost:3000"
      />
      <input
        class="publish-input"
        v-model="roomId"
        placeholder="请输入房间ID，例如：room1"
        style="margin-top: 10rpx;"
      />
    </view>

    <view class="status-info">
      <text>状态: {{ statusText }} {{ publishStatus }}</text>
    </view>
    
    <!-- 连接用户列表 -->
    <view class="users-info" v-if="connectedUsers.length > 0">
      <text>房间用户 ({{ connectedUsers.length }}):</text>
      <view class="user-list">
        <text v-for="(user, index) in connectedUsers" :key="index" class="user-item">
          {{ user.userId }} ({{ user.role }})
        </text>
      </view>
    </view>
  </view>
</template>

<script>
import { monitorFace } from '@/api/attendance.js'
import { getUserRealName } from '@/utils/auth.js'

export default {
  data() {
    return {
      localStream: null,
      testStream: null,
      status: 'pending', // pending, granted, denied, error, stopped
      errorMessage: '',
      // 推流相关变量
      isPublishing: false,
      publishUrl: 'http://1.94.105.36:3000', // 默认信令服务器地址
      srsServerUrl: 'http://1.94.105.36:1985', // SRS服务器地址
      publishStatus: '',
      // WebRTC相关变量
      peerConnection: null,
      playerPeerConnection: null,
      signalingConnection: null,
      roomId: this.getRoomIdFromUrl(), // 从URL获取房间ID
      sdpConstraints: {
        mandatory: {
          OfferToReceiveAudio: false,
          OfferToReceiveVideo: false
        }
      },
      playerSdpConstraints: {
        offerToReceiveAudio: true,
        offerToReceiveVideo: true,
        voiceActivityDetection: false
      },
      // 连接用户相关
      connectedUsers: [],
      // 连接状态
      connectionTimeout: null,
      // 当前使用的流类型 (camera or screen)
      currentStreamType: 'camera',
      // SRS SDK 实例 - 使用Map管理，key为streamId
      sdkInstances: new Map(),
      // 播放流列表 - 改为对象数组，包含唯一标识
      playStreams: [],
      sdk: null,
      // 观众流管理
      audienceStreams: [], // 存储观众流信息
      audienceSdks: new Map(), // 使用Map存储观众SDK实例，key为userId
      // 设备控制状态
      deviceControlEnabled: true, // 是否启用设备控制功能
      // 学生列表（从sessionStorage获取）
      studentList: [],
      studentIdList: [],
      // 摄像头控制相关
      userCameraStatus: new Map(), // 存储每个用户的摄像头状态 userId -> 'enabled'/'disabled'
      cameraControlRequests: new Map(), // 存储待处理的摄像头控制请求
      // 签到相关状态
      attendanceInProgress: false,
      attendanceResults: null,
      
      // 弹幕相关
      danmakuList: [], // 弹幕列表（历史记录）
      scrollingDanmakuList: [], // 滚动弹幕列表
      inputMessage: '', // 输入消息
      isDanmakuEnabled: true, // 弹幕开关
      danmakuScrollTop: 0, // 弹幕滚动位置
      
      // 弹幕设置
      danmakuColors: ['#ffffff', '#ff0000', '#00ff00', '#0000ff', '#ffff00', '#ff00ff'],
      selectedColor: '#ffffff',
      selectedSize: 'medium', // small, medium, large
      danmakuPosition: 'full', // full, top, bottom
      
      // WebSocket相关
      websocket: null,
      websocketConnected: false,
      websocketTask: null,
      
      // 全屏相关
      isFullscreen: false, // 是否处于全屏状态
      
      // 直播标题
      liveTitle: '直播间标题AAA', // 直播标题属性
      
      // 在线监控相关
      monitoringEnabled: false, // 是否启用监控
      monitoringInterval: null, // 监控定时器
      monitoringIntervalTime: 10000, // 监控间隔时间（毫秒），默认1分钟
      studentScreenshots: new Map(), // 存储学生截图数据 userId -> {timestamp, imageData, isPresent}
      monitoringResults: [], // 监控结果记录
      
      // 推流监控记录系统
      streamingSessionActive: false, // 当前是否在推流会话中
      streamingStartTime: null, // 推流开始时间
      streamingEndTime: null, // 推流结束时间
      studentMonitoringStats: new Map(), // 学生监控统计 userId -> {monitoringSuccess: 0, monitoringFailed: 0, streamConnected: 0, streamDisconnected: 0, studentName: ''}
      sessionMonitoringLog: [], // 本次会话的监控日志
      sessionStreamLog: [] // 本次会话的流连接日志
    }
  },

  computed: {
    statusText() {
      switch(this.status) {
        case 'pending': return '正在获取权限...'
        case 'granted': return '已获取权限，正在预览...'
        case 'denied': return '权限被拒绝'
        case 'error': return '发生错误'
        case 'stopped': return '已停止'
        default: return '未知状态'
      }
    },
    
    // 观众数统计
    audienceCount() {
      // 计算当前在线的观众数（有流且不是占位符）
      const onlineCount = this.audienceStreams.filter(stream => 
        stream.hasStream && !stream.isPlaceholder
      ).length;
      
      // 应到人数为studentList的长度
      const totalCount = this.studentList.length;
      
      return `${onlineCount}/${totalCount}`;
    },

    // 使用计算属性动态生成本地视频元素
    localVideoElement() {
      if (this.localStream) {
        // 返回带有唯一ID的video元素，稍后通过DOM操作设置srcObject
        return `<video id="localVideo" class="local-video-player" autoplay muted playsinline controls style="object-fit: fill; background-color: #000; position: relative; margin: 0 auto; display: block; width: 75%; height: 75%;"></video>`;
      }
      return ''; // 没有流时返回空字符串.
    },
    
  },

  watch: {
    // 监听localStream变化，当有新的媒体流时设置到video元素
    localStream(newStream) {
      if (newStream) {
        this.setStreamToVideo();
      }
    },
    
  },

  mounted() {
    // 从sessionStorage加载学生列表
    this.loadStudentListFromStorage();
    
    // 页面加载完成后自动获取媒体权限
    this.$nextTick(() => {
      this.initStream();
    });
    
    // 连接WebSocket
    this.connectWebSocket();
    
    // 添加一些测试弹幕
    this.addTestDanmaku();
    
    // 监听全屏状态变化
    this.setupFullscreenListeners();
    
    // 初始化学生占位符
    this.initStudentPlaceholders();
  },

  methods: {
    // 从URL获取房间ID
    getRoomIdFromUrl() {
      try {
        // 获取URL参数
        const urlParams = new URLSearchParams(window.location.search);
        const classCode = urlParams.get('classCode');
        
        if (classCode) {
          console.log('从URL获取到classCode:', classCode);
          return classCode;
        }
        
        // 如果没有classCode参数，使用默认值
        console.log('未找到classCode参数，使用默认房间ID');
        return '706392';
      } catch (error) {
        console.error('获取URL参数失败:', error);
        return '706392';
      }
    },
    
    // 从sessionStorage加载学生列表
    loadStudentListFromStorage() {
      try {
        // 从sessionStorage获取学生姓名列表
        const studentNamesStr = sessionStorage.getItem('studentNames');
        if (studentNamesStr) {
          this.studentList = JSON.parse(studentNamesStr);
          console.log('从sessionStorage加载学生姓名列表:', this.studentList);
        } else {
          // 如果没有找到，使用默认值
          this.studentList = ['学生1', '学生2', '学生3', '学生4', '学生5'];
          console.log('未找到studentNames，使用默认学生列表');
        }
        
        // 从sessionStorage获取学生ID列表
        const studentIdsStr = sessionStorage.getItem('studentIds');
        if (studentIdsStr) {
          this.studentIdList = JSON.parse(studentIdsStr);
          console.log('从sessionStorage加载学生ID列表:', this.studentIdList);
        } else {
          // 如果没有找到，生成默认ID
          this.studentIdList = this.studentList.map((_, index) => `student_${index + 1}`);
          console.log('未找到studentIds，生成默认学生ID列表');
        }
        
        // 确保两个列表长度一致
        if (this.studentList.length !== this.studentIdList.length) {
          console.warn('学生姓名和ID列表长度不一致，调整ID列表');
          this.studentIdList = this.studentList.map((_, index) => 
            this.studentIdList[index] || `student_${index + 1}`
          );
        }
        
        console.log('学生列表加载完成:', {
          studentList: this.studentList,
          studentIdList: this.studentIdList,
          count: this.studentList.length
        });
        
      } catch (error) {
        console.error('加载学生列表失败:', error);
        // 使用默认值
        this.studentList = ['学生1', '学生2', '学生3', '学生4', '学生5'];
        this.studentIdList = ['student_1', 'student_2', 'student_3', 'student_4', 'student_5'];
      }
    },
    
    // 初始化学生占位符
    initStudentPlaceholders() {
      this.audienceStreams = [];
      this.studentList.forEach((studentName, index) => {
        const studentId = this.studentIdList[index] || `student_${index + 1}`;
        const streamInfo = {
          userId: `socket_${Date.now()}_${index}`, // socketId，用于WebRTC连接
          studentId: studentId, // 学生ID，用于监控和统计
          studentName: studentName,
          streamId: null,
          hasStream: false, // 标记为占位符状态
          isPlaceholder: true, // 标记为占位符
          monitoringStatus: 'normal', // 监控状态: normal, away, offline
          cameraEnabled: true, // 摄像头状态
          micEnabled: true // 麦克风状态
        };
        this.audienceStreams.push(streamInfo);
      });
      console.log(`已初始化${this.studentList.length}个学生占位符:`, this.audienceStreams);
    },

    // 替换学生占位符
    replaceStudentPlaceholder(realUserId, realStudentName, realStudentId = null) {
      // 优先查找同studentId的占位符
      let placeholderIndex = -1;
      if (realStudentId) {
        placeholderIndex = this.audienceStreams.findIndex(stream => 
          stream.isPlaceholder && !stream.hasStream && stream.studentId === realStudentId
        );
      }
      
      // 如果没有找到同studentId的占位符，查找第一个空闲的占位符
      if (placeholderIndex === -1) {
        placeholderIndex = this.audienceStreams.findIndex(stream => 
          stream.isPlaceholder && !stream.hasStream
        );
      }
      
      if (placeholderIndex !== -1) {
        // 替换占位符为真实学生
        const placeholder = this.audienceStreams[placeholderIndex];
        const originalName = placeholder.studentName; // 保存原始占位符名字
        placeholder.userId = realUserId; // socketId，用于WebRTC连接
        placeholder.studentName = realStudentName;
        placeholder.studentId = realStudentId || placeholder.studentId; // 保持原有的studentId或使用新的
        placeholder.isPlaceholder = false;
        placeholder.hasStream = false; // 初始状态为无流，等待流连接
        placeholder.originalPlaceholderName = originalName; // 保存原始名字以便恢复
        placeholder.monitoringStatus = 'normal'; // 初始监控状态为正常
        placeholder.cameraEnabled = true; // 初始摄像头状态
        placeholder.micEnabled = true; // 初始麦克风状态
        
        console.log(`占位符已被替换: ${originalName} -> ${realStudentName} (socketId: ${realUserId}, studentId: ${placeholder.studentId})`);
      } else {
        console.log('没有可用的占位符，添加新的学生流');
        // 如果没有空闲占位符，直接添加
        this.audienceStreams.push({
          userId: realUserId, // socketId
          studentName: realStudentName,
          studentId: realStudentId || `student_${Date.now()}`,
          streamId: null,
          hasStream: false,
          isPlaceholder: false,
          monitoringStatus: 'normal',
          cameraEnabled: true, // 初始摄像头状态
          micEnabled: true // 初始麦克风状态
        });
      }
    },

    // 将真实学生转换回占位符
    convertToPlaceholder(userId) {
      const streamIndex = this.audienceStreams.findIndex(stream => stream.userId === userId);
      
      if (streamIndex !== -1) {
        const stream = this.audienceStreams[streamIndex];
        
        // 如果有SDK实例，先关闭
        if (this.audienceSdks.has(userId)) {
          try {
            const sdk = this.audienceSdks.get(userId);
            sdk.close();
            this.audienceSdks.delete(userId);
            console.log(`关闭用户 ${userId} 的观众流SDK`);
          } catch (error) {
            console.error(`关闭用户 ${userId} 的观众流SDK失败:`, error);
          }
        }
        
        // 恢复为占位符状态
        const originalName = stream.originalPlaceholderName || this.studentList[streamIndex] || `学生${streamIndex + 1}`;
        stream.userId = `student_${streamIndex + 1}`;
        stream.studentName = originalName;
        stream.streamId = null;
        stream.hasStream = false;
        stream.isPlaceholder = true;
        delete stream.originalPlaceholderName;
        
        console.log(`用户 ${userId} 已转换回占位符: ${originalName}`);
      }
    },

    // 生成观众视频元素
    getAudienceVideoElement(userId) {
      const videoId = 'audience_video_' + userId;
      return `<video id="${videoId}" class="video-player" controls autoplay width="100%" height="90%" style="object-fit: contain; background-color: #000;"></video>`;
    },

    /**
     * 动态加载SDK模块
     * 该方法使用script标签方式加载所需的SDK文件
     * @returns {Promise} 返回一个Promise，当所有SDK加载完成后resolve
     */
    async loadSDK() {
      try {
        console.log('开始动态加载SDK');
        
        // 检查是否已经加载过SDK
        if (typeof SrsRtcWhipWhepAsync !== 'undefined') {
          console.log('SDK已经加载，跳过重复加载');
          return;
        }
        
        // 使用script标签顺序加载SDK文件
        await this.loadScript('/static/js/adapter-7.4.0.min.js');
        console.log('adapter-7.4.0.min.js 加载完成');
        
        await this.loadScript('/static/js/winlin.utility.js');
        console.log('winlin.utility.js 加载完成');
        
        await this.loadScript('/static/js/srs.sdk.js');
        console.log('srs.sdk.js 加载完成');
        
        console.log('SRS SDK 加载完成，SrsRtcWhipWhepAsync:', typeof SrsRtcWhipWhepAsync);
      } catch (error) {
        console.error('加载SDK失败:', error);
        throw new Error(`SDK加载失败: ${error.message}`);
      }
    },
    
    // 动态加载JavaScript文件
    loadScript(src) {
      return new Promise((resolve, reject) => {
        const script = document.createElement('script');
        script.src = src;
        script.onload = resolve;
        script.onerror = reject;
        document.head.appendChild(script);
      });
    },
    async initStream() {
      try {
        this.status = 'pending';

        // 检查浏览器是否支持
        if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
          throw new Error('当前环境不支持媒体设备访问');
        }

        // 获取摄像头和麦克风权限
        this.localStream = await navigator.mediaDevices.getUserMedia({
          audio: true,
          video: true,
        });

        this.status = 'granted';
      } catch (error) {
        console.error('获取媒体流失败:', error);
        this.errorMessage = error.message || '获取媒体权限失败';
        if (error.name === 'NotAllowedError' || error.name === 'PermissionDeniedError') {
          this.status = 'denied';
        } else {
          this.status = 'error';
        }
      }
    },
    
    // 远程视频加载完成事件
    onRemoteVideoLoaded(event) {
      console.log('远程视频加载完成:', event);
      const videoElement = event.target;
      if (videoElement && typeof videoElement.play === 'function') {
        // 尝试播放视频
        const playPromise = videoElement.play();
        if (playPromise !== undefined) {
          playPromise.catch(error => {
            console.warn('远程视频播放被阻止:', error);
            videoElement.muted = true;
            videoElement.controls = true;
          });
        }
      }
    },
    
    // 将媒体流设置到video元素
    setStreamToVideo() {
      if (this.localStream) {
        this.$nextTick(() => {
          // 等待DOM更新完成后再次使用nextTick确保v-html内容已渲染
          this.$nextTick(() => {
            const videoElement = document.getElementById('localVideo');
            console.log('查找video元素:', videoElement);
            console.log('当前流状态:', this.localStream);
            if (videoElement) {
              videoElement.srcObject = this.localStream;
              console.log('已设置视频流到元素');
              
              // 尝试播放
              const playPromise = videoElement.play();
              if (playPromise !== undefined) {
                playPromise.catch(error => {
                  console.warn('本地视频播放被阻止:', error);
                });
              }
              
              // 强制显示控件
              videoElement.controls = true;
            } else {
              console.log('本地视频元素未找到');
            }
          });
        });
      }
    },

    startStream() {
      this.initStream();
    },

    stopStream() {
      // 停止推流（如果正在进行）
      this.stopPublishing();
      
      if (this.localStream) {
        // 停止所有轨道
        const tracks = this.localStream.getTracks();
        tracks.forEach(track => track.stop());
        this.localStream = null;
        this.status = 'stopped';
      }
    },
    
    // 开始推流到WebRTC服务器
    async startPublishing() {
      if (!this.localStream) {
        this.publishStatus = '错误：没有可用的媒体流';
        return;
      }
      
      if (!this.publishUrl) {
        this.publishStatus = '错误：请输入信令服务器地址';
        return;
      }
      
      try {
        this.isPublishing = true;
        this.publishStatus = '正在连接信令服务器...';
        
        // 连接信令服务器
        await this.connectSignalingServer();
        
        // 创建RTCPeerConnection
        await this.createPeerConnection();
        
        // 添加本地流到PeerConnection
        this.localStream.getTracks().forEach(track => {
          this.peerConnection.addTrack(track, this.localStream);
        });
        
        // 创建并发送offer到SRS服务器（通过信令服务器中转）
        const offer = await this.peerConnection.createOffer(this.sdpConstraints);
        await this.peerConnection.setLocalDescription(offer);
        
        console.log('发送SDP Offer到SRS服务器');
        // 通过信令服务器发送offer到SRS服务器
        this.signalingConnection.emit('srs-offer', {
          sdp: offer.sdp,
          type: offer.type,
          roomId: this.roomId
        });
        
        this.publishStatus = `正在推流到: ${this.publishUrl}, 房间: ${this.roomId}`;
        
        // 启动推流监控记录系统
        this.startStreamingSession();
        
      } catch (error) {
        console.error('推流失败:', error);
        this.publishStatus = `推流失败: ${error.message}`;
        this.isPublishing = false;
      }
    },
    
    // 连接信令服务器 (使用Socket.IO)
    connectSignalingServer() {
      return new Promise((resolve, reject) => {
        try {
          // 动态导入socket.io-client
          import('socket.io-client').then((module) => {
            const io = module.io || module.default || module;
            
            // 如果已经连接，则直接resolve
            if (this.signalingConnection && this.signalingConnection.connected) {
              console.log('信令服务器已连接，使用现有连接');
              // 重新加入房间
              const role = this.isPublishing ? 'publisher' : 'publisher';
              this.signalingConnection.emit('join-room', {
                roomId: this.roomId,
                role: role
              });
              resolve();
              return;
            }
            
            // 连接Socket.IO服务器
            this.signalingConnection = io(this.publishUrl, {
              transports: ['websocket', 'polling'],
              reconnection: true,
              reconnectionAttempts: 5,
              reconnectionDelay: 1000,
              timeout: 10000 // 10秒连接超时
            });
            
            // 监听连接成功事件
            this.signalingConnection.on('connect', () => {
              console.log('信令服务器连接成功，Socket ID:', this.signalingConnection.id);
              this.publishStatus = '信令服务器连接成功，正在建立WebRTC连接...';
              
              // 加入房间，指定角色为发布者或观看者
              const role = this.isPublishing ? 'publisher' : 'publisher';
              this.signalingConnection.emit('join-room', {
                roomId: this.roomId,
                role: role
              });
              resolve();
            });
            
            // 监听连接错误事件
            this.signalingConnection.on('connect_error', (error) => {
              console.error('信令服务器连接错误:', error);
              this.publishStatus = '信令服务器连接失败: ' + error.message;
              reject(new Error('信令服务器连接失败: ' + error.message));
            });
            
            // 监听连接超时
            this.signalingConnection.on('connect_timeout', (timeout) => {
              console.error('信令服务器连接超时:', timeout);
              this.publishStatus = '信令服务器连接超时: ' + timeout;
              reject(new Error('信令服务器连接超时: ' + timeout));
            });
            
            // 监听断开连接事件
            this.signalingConnection.on('disconnect', (reason) => {
              console.log('信令服务器断开连接，原因:', reason);
              if (this.isPublishing) {
                this.publishStatus = '信令服务器连接已断开: ' + reason;
                // 不要自动设置为false，让用户手动控制
              }
            });
            
            // 监听SRS服务器的answer（发布用）
            this.signalingConnection.on('srs-answer', (data) => {
              console.log('收到SRS服务器的发布Answer');
              this.handleAnswer(data);
            });
            
            // 监听SRS服务器的answer（观看用）
            this.signalingConnection.on('player-answer', (data) => {
              console.log('收到SRS服务器的观看Answer');
              this.handlePlayerAnswer(data);
            });
            
            // 监听ICE候选
            this.signalingConnection.on('ice-candidate', (data) => {
              console.log('收到ICE候选');
              this.handleCandidate(data);
            });
            
            // 监听错误消息
            this.signalingConnection.on('error', (data) => {
              console.error('信令服务器错误:', data);
              this.publishStatus = '信令服务器错误: ' + (data.message || '未知错误');
              if (data.details) {
                this.publishStatus += ' (' + JSON.stringify(data.details) + ')';
              }
              
              // 处理特定错误
              if (data.code === 'ROOM_OCCUPIED') {
                this.isPublishing = false;
              }
            });
            
            // 监听用户连接事件
            this.signalingConnection.on('user-connected', (data) => {
              console.log('新用户连接:', data);
              // 更新用户列表
              const existingUser = this.connectedUsers.find(user => user.userId === data.userId);
              if (!existingUser) {
                this.connectedUsers.push(data);
              }
              
              // 为新连接的观众替换占位符
              if (data.userId && data.role === 'player') {
                console.log(`学生 ${data.userId} 连接，准备替换占位符`);
                this.replaceStudentPlaceholder(data.userId, data.studentName || data.userId, data.studentId);
                
                // 记录流连接状态
                this.recordStreamConnection(data.studentId || data.userId, data.studentName || data.userId, true);
              }
            });
            
            // 监听房间信息
            this.signalingConnection.on('room-info', (data) => {
              console.log('房间信息:', data);
            });
            
            // 监听流可用事件
            this.signalingConnection.on('player-stream-available', (data) => {
              console.log('player流可用:', data);
              this.publishStatus = `推流中，房间: ${this.roomId}`;
              
              // 如果是观众流，添加到观众流列表，并更新studentName和studentId
              this.addSingleAudienceStream(data.playerId, data.studentName, data.studentId);
              
              // 记录流连接状态
              this.recordStreamConnection(data.studentId || data.playerId, data.studentName || data.playerId, true);
            });
            
            // 监听流不可用事件
            this.signalingConnection.on('player-stream-unavailable', (data) => {
              console.log('player流不可用:', data);
              // 移除isPlaying相关逻辑
              this.publishStatus = '流已断开';
              
              // 如果是观众流不可用，更新流状态为占位符
              if (data.userId && data.role === 'player') {
                const streamInfo = this.audienceStreams.find(stream => stream.userId === data.userId);
                if (streamInfo) {
                  // 停止SDK
                  if (this.audienceSdks.has(data.userId)) {
                    try {
                      const sdk = this.audienceSdks.get(data.userId);
                      sdk.close();
                      this.audienceSdks.delete(data.userId);
                    } catch (error) {
                      console.error(`停止用户 ${data.userId} 的观众流SDK失败:`, error);
                    }
                  }
                  
                  // 更新为占位符状态
                  streamInfo.hasStream = false;
                  streamInfo.streamId = null;
                  console.log(`用户 ${data.userId} 的观众流已停止，转为占位符状态`);
                  
                  // 记录流断开状态
                  this.recordStreamConnection(data.studentId || data.userId, data.studentName || data.userId, false);
                }
              }
            });
            
            // 监听用户断开事件
            this.signalingConnection.on('user-disconnected', (data) => {
              console.log('用户断开连接:', data);
              // 从用户列表中移除
              const index = this.connectedUsers.findIndex(user => user.userId === data.userId);
              if (index !== -1) {
                this.connectedUsers.splice(index, 1);
              }
              
              // 根据变更类型精确处理，避免全量刷新
              if (data.changeType === 'publisher_left') {
                // 发布者离开，停止所有播放
                // 移除stopPlaying调用
                this.publishStatus = '发布者已离开';
              } else if (data.changeType === 'player_left') {
                // 观看者离开，将其重新变为占位符
                console.log(`观看者 ${data.userId} 离开房间`);
                this.convertToPlaceholder(data.userId);
                
                // 记录流断开状态
                this.recordStreamConnection(data.studentId || data.userId, data.studentName || data.userId, false);
              }
            });
            
            // 监听签到结果
            this.signalingConnection.on('attendance-results', (data) => {
              console.log('收到签到结果:', data);
              this.handleAttendanceResult(data);
            });
            
            // 监听签到取消
            this.signalingConnection.on('attendance-cancelled', (data) => {
              console.log('签到已取消:', data);
              this.attendanceInProgress = false;
              uni.showToast({
                title: '签到已取消',
                icon: 'none'
              });
            });
          }).catch((error) => {
            console.error('导入Socket.IO客户端失败:', error);
            let errorMessage = '导入Socket.IO客户端失败: ';
                    
            if (error.message) {
              errorMessage += error.message;
            } else {
              errorMessage += '未知错误';
            }
                    
            // 特定错误处理
            if (error.code === 'MODULE_NOT_FOUND') {
              errorMessage = 'Socket.IO客户端模块未找到，请检查依赖是否正确安装';
            } else if (error.message.includes('NetworkError')) {
              errorMessage = '网络错误，无法加载Socket.IO客户端';
            }
                    
            this.publishStatus = errorMessage;
            reject(new Error(errorMessage));
                    
            // 显示友好的错误提示给用户
            uni.showToast({
              title: '加载失败',
              content: errorMessage,
              icon: 'none',
              duration: 5000,
              mask: true
            });
          });
        } catch (error) {
          console.error('创建Socket.IO连接时出错:', error);
          let errorMessage = '创建连接失败: ';
                
          if (error.message) {
            errorMessage += error.message;
          } else {
            errorMessage += '未知错误';
          }
                
          // 特殊错误处理
          if (error.code === 'ECONNREFUSED') {
            errorMessage = '连接被拒绝，请检查信令服务器是否正在运行';
          } else if (error.message.includes('timeout')) {
            errorMessage = '连接超时，请检查网络连接是否正常';
          } else if (error.message.includes('Invalid namespace')) {
            errorMessage = '无效的命名空间，请检查服务器地址是否正确';
          }
                
          this.publishStatus = errorMessage;
          reject(new Error(errorMessage));
        }
      });
    },
    
    // 创建RTCPeerConnection
    createPeerConnection() {
      console.log('开始创建RTCPeerConnection:', {
        configuration: {
          iceServers: [
            { urls: 'stun:stun.l.google.com:19302' } // 备用公共STUN服务器
          ]
        },
        timestamp: new Date().toISOString()
      });
      
      // 生成唯一连接ID用于日志跟踪
      const connectionId = `conn-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
      
      // 这里的配置需要根据你的SRS服务器配置进行调整
      const configuration = {
        iceServers: [
          { urls: 'stun:stun.l.google.com:19302' } // 备用公共STUN服务器
        ],
        bundlePolicy: 'max-bundle',  // 确保使用BUNDLE策略
        rtcpMuxPolicy: 'require'     // 确保使用RTCP多路复用
      };
      
      this.peerConnection = new RTCPeerConnection(configuration);
      
      // 添加连接ID到对象，方便日志跟踪
      if (this.peerConnection && !this.peerConnection.connectionId) {
        Object.defineProperty(this.peerConnection, 'connectionId', {
          value: connectionId,
          configurable: false,
          writable: false,
          enumerable: true
        });
      }
      
      console.log('RTCPeerConnection创建成功:', {
        connectionId: connectionId,
        configuration: configuration,
        timestamp: new Date().toISOString()
      });
      
      // ICE候选处理
      this.peerConnection.onicecandidate = (event) => {
        if (event.candidate && this.signalingConnection) {
          console.log('生成新的ICE候选:', {
            candidate: event.candidate,
            connectionId: this.peerConnection.connectionId,
            timestamp: new Date().toISOString()
          });
          
          // 使用Socket.IO的emit方法直接发送
          this.signalingConnection.emit('ice-candidate', {
            candidate: event.candidate,
            roomId: this.roomId
          });
          
          console.log('ICE候选已发送:', {
            candidate: event.candidate,
            roomId: this.roomId,
            connectionId: this.peerConnection.connectionId,
            timestamp: new Date().toISOString()
          });
        } else if (!event.candidate) {
          console.log('ICE候选收集完成:', {
            connectionId: this.peerConnection.connectionId,
            timestamp: new Date().toISOString()
          });
        }
      };
      
      // 连接状态变化处理
      this.peerConnection.onconnectionstatechange = () => {
        const currentState = this.peerConnection.connectionState;
        console.log('WebRTC连接状态变化:', {
          connectionId: this.peerConnection.connectionId,
          newState: currentState,
          previousState: this.previousConnectionState,
          timestamp: new Date().toISOString()
        });
        
        this.previousConnectionState = currentState;
        
        if (currentState === 'connected') {
          this.publishStatus = `推流中: ${this.publishUrl}, 房间: ${this.roomId}`;
          
          console.log('数据通道状态详细信息:', {
            connectionId: this.peerConnection.connectionId,
            iceConnectionState: this.peerConnection.iceConnectionState,
            signalingState: this.peerConnection.signalingState,
            timestamp: new Date().toISOString()
          });
          
          // 连接成功后发送状态更新
          this.signalingConnection.emit('publisher_status', {
            status: 'connected',
            roomId: this.roomId
          });
          
          console.log('连接建立成功:', {
            connectionId: this.peerConnection.connectionId,
            roomId: this.roomId,
            timestamp: new Date().toISOString()
          });
        } else if (currentState === 'failed') {
          console.error('WebRTC连接失败:', {
            connectionId: this.peerConnection.connectionId,
            iceConnectionState: this.peerConnection.iceConnectionState,
            timestamp: new Date().toISOString()
          });
          
          this.publishStatus = 'WebRTC连接失败';
          this.stopPublishing();
          
          // 发送错误状态
          this.signalingConnection.emit('publisher_status', {
            status: 'failed',
            roomId: this.roomId,
            error: 'WebRTC连接失败'
          });
          
          console.error('连接失败通知:', {
            connectionId: this.peerConnection.connectionId,
            roomId: this.roomId,
            iceConnectionState: this.peerConnection.iceConnectionState,
            timestamp: new Date().toISOString()
          });
        } else if (currentState === 'disconnected') {
          console.warn('连接断开，尝试重新连接:', {
            connectionId: this.peerConnection.connectionId,
            previousState: this.previousConnectionState,
            timestamp: new Date().toISOString()
          });
          
          this.publishStatus = '连接断开，正在尝试重新连接...';
          
          // 发送断开状态
          this.signalingConnection.emit('publisher_status', {
            status: 'disconnected',
            roomId: this.roomId
          });
          
          console.warn('连接断开通知:', {
            connectionId: this.peerConnection.connectionId,
            roomId: this.roomId,
            timestamp: new Date().toISOString()
          });
        } else if (currentState === 'closed') {
          console.log('连接已关闭:', {
            connectionId: this.peerConnection.connectionId,
            timestamp: new Date().toISOString()
          });
        }
      };
      
      // ICE连接状态变化处理
      this.peerConnection.oniceconnectionstatechange = () => {
        const currentState = this.peerConnection.iceConnectionState;
        console.log('ICE连接状态变化:', {
          connectionId: this.peerConnection.connectionId,
          newState: currentState,
          previousIceState: this.previousIceState,
          timestamp: new Date().toISOString()
        });
        
        this.previousIceState = currentState;
        
        if (currentState === 'failed') {
          console.error('ICE连接失败:', {
            connectionId: this.peerConnection.connectionId,
            connectionState: this.peerConnection.connectionState,
            timestamp: new Date().toISOString()
          });
          
          this.publishStatus = 'ICE连接失败';
          this.stopPublishing();
          
          // 发送错误状态
          this.signalingConnection.emit('publisher_status', {
            status: 'failed',
            roomId: this.roomId,
            error: 'ICE连接失败'
          });
          
          console.error('ICE失败通知:', {
            connectionId: this.peerConnection.connectionId,
            roomId: this.roomId,
            timestamp: new Date().toISOString()
          });
        } else if (currentState === 'disconnected') {
          console.warn('ICE连接断开:', {
            connectionId: this.peerConnection.connectionId,
            previousState: this.previousIceState,
            timestamp: new Date().toISOString()
          });
          
          this.publishStatus = 'ICE连接断开';
          
          // 发送断开状态
          this.signalingConnection.emit('publisher_status', {
            status: 'disconnected',
            roomId: this.roomId
          });
          
          console.warn('ICE断开通知:', {
            connectionId: this.peerConnection.connectionId,
            roomId: this.roomId,
            timestamp: new Date().toISOString()
          });
        } else if (currentState === 'closed') {
          console.log('ICE连接已关闭:', {
            connectionId: this.peerConnection.connectionId,
            timestamp: new Date().toISOString()
          });
        }
      };
      
      // ICE收集状态变化处理
      this.peerConnection.onicegatheringstatechange = () => {
        const currentState = this.peerConnection.iceGatheringState;
        console.log('ICE收集状态变化:', {
          connectionId: this.peerConnection.connectionId,
          newState: currentState,
          previousIceGatherState: this.previousIceGatherState,
          timestamp: new Date().toISOString()
        });
        
        this.previousIceGatherState = currentState;
        
        if (currentState === 'complete') {
          console.log('ICE收集完成:', {
            connectionId: this.peerConnection.connectionId,
            timestamp: new Date().toISOString()
          });
          
          // 发送ICE完成状态
          this.signalingConnection.emit('ice-gathering-complete', {
            roomId: this.roomId
          });
        }
      };
      
      // 信令状态变化处理
      this.peerConnection.onsignalingstatechange = () => {
        const currentState = this.peerConnection.signalingState;
        console.log('信令状态变化:', {
          connectionId: this.peerConnection.connectionId,
          newState: currentState,
          previousSignalingState: this.previousSignalingState,
          timestamp: new Date().toISOString()
        });
        
        this.previousSignalingState = currentState;
        
        if (currentState === 'stable') {
          console.log('信令状态稳定:', {
            connectionId: this.peerConnection.connectionId,
            timestamp: new Date().toISOString()
          });
        } else if (currentState === 'have-local-offer') {
          console.log('已创建本地Offer:', {
            connectionId: this.peerConnection.connectionId,
            timestamp: new Date().toISOString()
          });
        } else if (currentState === 'have-remote-offer') {
          console.log('收到远程Offer:', {
            connectionId: this.peerConnection.connectionId,
            timestamp: new Date().toISOString()
          });
        } else if (currentState === 'have-local-answer') {
          console.log('已创建本地Answer:', {
            connectionId: this.peerConnection.connectionId,
            timestamp: new Date().toISOString()
          });
        } else if (currentState === 'have-remote-answer') {
          console.log('收到远程Answer:', {
            connectionId: this.peerConnection.connectionId,
            timestamp: new Date().toISOString()
          });
        }
      };
      
      // 数据通道状态变化处理
      this.peerConnection.ondatachannel = (event) => {
        console.log('数据通道已创建');
        this.dataChannel = event.channel;
        
        this.dataChannel.onopen = () => {
          console.log('数据通道已打开');
          this.publishStatus = '数据通道已打开，正在推流中...';
          
          // 发送通道状态
          this.signalingConnection.emit('data_channel_status', {
            status: 'open',
            roomId: this.roomId
          });
        };
        
        this.dataChannel.onclose = () => {
          console.log('数据通道已关闭');
          this.publishStatus = '数据通道已关闭';
          
          // 发送通道状态
          this.signalingConnection.emit('data_channel_status', {
            status: 'closed',
            roomId: this.roomId
          });
        };
        
        this.dataChannel.onerror = (error) => {
          console.error('数据通道错误:', error);
          this.publishStatus = '数据通道错误: ' + error.message;
          
          // 发送通道状态
          this.signalingConnection.emit('data_channel_status', {
            status: 'error',
            roomId: this.roomId,
            error: error.message
          });
        };
      };
      
      // 数据通道状态变化处理
      this.peerConnection.ondatachannel = (event) => {
        console.log('数据通道已创建');
        this.dataChannel = event.channel;
        
        this.dataChannel.onopen = () => {
          console.log('数据通道已打开');
          this.publishStatus = '数据通道已打开，正在推流中...';
          
          // 发送通道状态
          this.signalingConnection.emit('data_channel_status', {
            status: 'open',
            roomId: this.roomId
          });
        };
        
        this.dataChannel.onclose = () => {
          console.log('数据通道已关闭');
          this.publishStatus = '数据通道已关闭';
          
          // 发送通道状态
          this.signalingConnection.emit('data_channel_status', {
            status: 'closed',
            roomId: this.roomId
          });
        };
        
        this.dataChannel.onerror = (error) => {
          console.error('数据通道错误:', error);
          this.publishStatus = '数据通道错误: ' + error.message;
          
          // 发送通道状态
          this.signalingConnection.emit('data_channel_status', {
            status: 'error',
            roomId: this.roomId,
            error: error.message
          });
        };
      };
    },
    
    // 设置Socket.IO事件监听器
    setupSocketIOListeners() {
      // 处理远程Answer
      this.signalingConnection.on('sdp-answer', (data) => {
        console.log('收到SDP Answer:', {
          hasSdp: !!data.sdp,
          roomId: data.roomId,
          type: data.type,
          timestamp: new Date().toISOString()
        });
        
        // 验证roomId是否匹配
        if (data.roomId !== this.roomId) {
          console.warn('忽略其他房间的answer:', {
            receivedRoomId: data.roomId,
            expectedRoomId: this.roomId,
            timestamp: new Date().toISOString()
          });
          return;
        }
        
        console.log('准备处理SDP Answer:', {
          sdp: data.sdp,
          roomId: data.roomId,
          timestamp: new Date().toISOString()
        });
        
        this.handleAnswer(data);
      });
      
      // 处理ICE候选
      this.signalingConnection.on('ice-candidate', (data) => {
        console.log('收到ICE候选:', {
          hasCandidate: !!data.candidate,
          roomId: data.roomId,
          timestamp: new Date().toISOString()
        });
        
        // 验证roomId是否匹配
        if (data.roomId !== this.roomId) {
          console.warn('忽略其他房间的ICE候选:', {
            receivedRoomId: data.roomId,
            expectedRoomId: this.roomId,
            timestamp: new Date().toISOString()
          });
          return;
        }
        
        console.log('准备处理ICE候选:', {
          candidate: data.candidate,
          roomId: data.roomId,
          timestamp: new Date().toISOString()
        });
        
        this.handleCandidate(data);
      });
      
      // 处理错误
      this.signalingConnection.on('error', (error) => {
        console.error('Socket.IO错误:', error);
        this.publishStatus = '信令服务器错误: ' + (error.message || '未知错误');
        this.isPublishing = false;
      });
      
      // 初始化摄像头控制监听器
      this.setupCameraControlListeners();
      
      // 处理服务器断开事件
      this.signalingConnection.on('server-disconnected', (reason) => {
        console.warn('服务器断开连接:', reason);
        this.publishStatus = `服务器断开连接: ${reason}`;
        this.isPublishing = false;
      });
    },
    
    // 处理Offer
    async handleOffer(data) {
      try {
        console.log('开始处理SDP Offer:', {
          sdp: data.sdp,
          roomId: data.roomId,
          timestamp: new Date().toISOString()
        });
        
        if (this.peerConnection) {
          console.log('设置远程描述开始:', {
            connectionId: this.peerConnection.connectionId || 'N/A',
            timestamp: new Date().toISOString()
          });
          
          // 修改SDP以适配SRS服务器
          const modifiedSdp = this.adaptSdpForSRS(data.sdp);
          
          await this.peerConnection.setRemoteDescription(
            new RTCSessionDescription({ type: 'offer', sdp: modifiedSdp })
          );
          
          console.log('创建answer开始:', {
            connectionId: this.peerConnection.connectionId || 'N/A',
            timestamp: new Date().toISOString()
          });
          
          const answer = await this.peerConnection.createAnswer();
          
          console.log('设置本地描述开始:', {
            connectionId: this.peerConnection.connectionId || 'N/A',
            answerType: answer.type,
            timestamp: new Date().toISOString()
          });
          
          // 修改Answer SDP以适配SRS服务器
          const modifiedAnswer = await this.peerConnection.createAnswer();
          const modifiedAnswerSdp = this.adaptSdpForSRS(modifiedAnswer.sdp);
          
          await this.peerConnection.setLocalDescription(
            new RTCSessionDescription({
              type: modifiedAnswer.type,
              sdp: modifiedAnswerSdp
            })
          );
          
          console.log('发送SDP Answer:', {
            answerType: modifiedAnswer.type,
            roomId: this.roomId,
            timestamp: new Date().toISOString()
          });
          
          // 发送answer
          this.signalingConnection.emit('srs-answer', {
            sdp: modifiedAnswerSdp,
            type: modifiedAnswer.type,
            roomId: this.roomId
          });
        }
      } catch (error) {
        console.error('处理Offer时出错:', {
          error: error,
          message: error.message,
          stack: error.stack,
          timestamp: new Date().toISOString()
        });
        this.publishStatus = '处理Offer失败: ' + error.message;
      }
    },
    
    // SDP适配SRS服务器
    adaptSdpForSRS(sdp) {
      // 这里可以根据SRS服务器的要求修改SDP
      // 例如：修改编解码器优先级、移除不支持的编解码器等
      
      // 示例：将H264设为首选视频编解码器
      let modifiedSdp = sdp.replace(/a=rtpmap:(\d+) VP8\/90000/g, 'a=rtpmap:$1 H264/90000');
      
      // 示例：移除不支持的音频编解码器
      modifiedSdp = modifiedSdp.replace(/a=rtpmap:.*G722.*\r\n/g, '');
      modifiedSdp = modifiedSdp.replace(/a=rtpmap:.*PCMU.*\r\n/g, '');
      modifiedSdp = modifiedSdp.replace(/a=rtpmap:.*PCMA.*\r\n/g, '');
      
      // 示例：修改视频配置参数
      modifiedSdp = modifiedSdp.replace(/a=fmtp:.*apt=.*\r\n/g, '');
      
      // 示例：添加SRS特定的扩展
      if (!modifiedSdp.includes('http://srs.com/rtc/' + this.roomId)) {
        modifiedSdp += `a=extmap:1 http://srs.com/rtc/${this.roomId}\r\n`;
      }
      
      return modifiedSdp;
    },
    
    // 处理Answer
    async handleAnswer(data) {
      try {
        console.log('开始处理SDP Answer:', {
          hasSdp: !!data.sdp,
          roomId: data.roomId,
          timestamp: new Date().toISOString()
        });
        
        if (this.peerConnection) {
          console.log('设置远程描述开始:', {
            connectionId: this.peerConnection.connectionId || 'N/A',
            timestamp: new Date().toISOString()
          });
          
          await this.peerConnection.setRemoteDescription(
            new RTCSessionDescription({ type: 'answer', sdp: data.sdp })
          );
          
          console.log('成功设置远程描述:', {
            connectionId: this.peerConnection.connectionId || 'N/A',
            timestamp: new Date().toISOString()
          });
        }
      } catch (error) {
        console.error('处理Answer时出错:', {
          error: error,
          message: error.message,
          stack: error.stack,
          timestamp: new Date().toISOString()
        });
        this.publishStatus = '处理Answer失败: ' + error.message;
      }
    },
    
    // 处理ICE候选
    handleCandidate(data) {
      try {
        console.log('开始处理ICE候选:', {
          hasCandidate: !!data.candidate,
          roomId: data.roomId,
          timestamp: new Date().toISOString()
        });
        
        if (this.peerConnection && data.candidate) {
          console.log('添加ICE候选:', {
            candidate: data.candidate,
            connectionId: this.peerConnection.connectionId || 'N/A',
            timestamp: new Date().toISOString()
          });
          
          this.peerConnection.addIceCandidate(new RTCIceCandidate(data.candidate));
          
          console.log('成功添加ICE候选:', {
            candidate: data.candidate,
            connectionId: this.peerConnection.connectionId || 'N/A',
            timestamp: new Date().toISOString()
          });
        }
      } catch (error) {
        console.error('处理ICE候选时出错:', {
          error: error,
          message: error.message,
          stack: error.stack,
          timestamp: new Date().toISOString()
        });
        this.publishStatus = '处理ICE候选失败: ' + error.message;
      }
    },
    
    // 切换视频流
    switchStream() {
      if (this.localStream) {
        // 切换流类型
        this.currentStreamType = this.currentStreamType === 'camera' ? 'screen' : 'camera';
        
        // 停止当前流的所有轨道
        const tracks = this.localStream.getTracks();
        tracks.forEach(track => track.stop());
        
        // 根据新的流类型获取媒体流
        this.initStream();
      }
    },
    
    // 停止推流
    stopPublishing() {
      if (this.isPublishing) {
        // 关闭WebRTC连接
        if (this.peerConnection) {
          this.peerConnection.close();
          this.peerConnection = null;
        }
        
        // 断开Socket.IO连接
        if (this.signalingConnection) {
          this.signalingConnection.disconnect();
          this.signalingConnection = null;
        }
        
        this.isPublishing = false;
        this.publishStatus = '已停止推流';
        console.log('已停止推流');
        
        // 结束推流监控记录系统并显示统计
        this.endStreamingSession();
      }
    },
    
    // 切换视频流（摄像头流 <-> 屏幕共享流）
    async switchStream() {
      try {
        // 如果当前使用的是摄像头流，则切换到屏幕共享流
        if (this.currentStreamType === 'camera') {
          // 如果还没有获取过屏幕共享流，则先获取
          if (!this.testStream) {
            this.testStream = await navigator.mediaDevices.getDisplayMedia({
              video: true,
              audio: true
            });
          }
          
          // 停止当前摄像头流的轨道
          if (this.localStream) {
            const tracks = this.localStream.getTracks();
            tracks.forEach(track => track.stop());
          }
          
          // 切换到屏幕共享流
          this.localStream = this.testStream;
          this.currentStreamType = 'screen';
          this.setStreamToVideo();
        } 
        // 如果当前使用的是屏幕共享流，则切换到摄像头流
        else {
          // 重新获取摄像头流
          this.localStream = await navigator.mediaDevices.getUserMedia({
            audio: true,
            video: true
          });
          
          this.currentStreamType = 'camera';
          this.setStreamToVideo();
        }
      } catch (error) {
        console.error('切换视频流失败:', error);
        this.publishStatus = '切换视频流失败: ' + error.message;
      }
    },


    

    
    // 使用SDK播放流列表
    async playStreamsWithSDK() {
      try {
        // 清除之前的远程流和SDK实例
        this.sdkInstances.forEach(sdk => sdk.close());
        this.sdkInstances.clear();
        
        // 使用SDK播放每个流
        for (const stream of this.playStreams) {
          console.log(`开始播放流 ${stream.streamId}:`, stream.url);
          
          // 创建新的SDK实例
          const sdk = new SrsRtcWhipWhepAsync();
          this.sdkInstances.set(stream.streamId, sdk);
          
          // 等待DOM更新
          await this.$nextTick();
          
          // 等待一段时间确保DOM完全渲染
          await new Promise(resolve => setTimeout(resolve, 100));
          
          // 获取视频元素
          const videoElement = document.getElementById(`remoteVideo_${stream.streamId}`);
          console.log(`尝试获取视频元素: remoteVideo_${stream.streamId}`, videoElement);
          if (videoElement) {
            // 将SDK的流设置为视频元素的源
            videoElement.srcObject = sdk.stream;
            
            // 开始播放
            try {
              const session = await sdk.play(stream.url);
              console.log(`播放成功 ${stream.streamId}:`, session);
              
              // 尝试播放视频
              const playPromise = videoElement.play();
              if (playPromise !== undefined) {
                playPromise.catch(error => {
                  console.warn('视频播放被阻止:', error);
                  videoElement.muted = true;
                  videoElement.controls = true;
                });
              }
            } catch (error) {
              console.error(`播放失败 ${stream.streamId}:`, error);
            }
          } else {
            console.error(`视频元素未找到: remoteVideo_${stream.streamId}`);
          }
        }
        
        this.publishStatus = `正在观看房间: ${this.roomId} (${this.playStreams.length}个流)`;
      } catch (error) {
        console.error('播放流列表失败:', error);
        this.publishStatus = `播放失败: ${error.message}`;
      }
    },
    
    // 创建并播放单个流
    async createAndPlaySingleStream(streamInfo) {
      console.log(`创建并播放单个流: ${streamInfo.streamId}`);
      
      try {
        // 创建新的SDK实例
        const sdk = new SrsRtcWhipWhepAsync();
        this.sdkInstances.set(streamInfo.streamId, sdk);
        
        // 等待DOM更新
        await this.$nextTick();
        await new Promise(resolve => setTimeout(resolve, 100));
        
        // 获取视频元素
        const videoElement = document.getElementById(`remoteVideo_${streamInfo.streamId}`);
        if (videoElement) {
          // 将SDK的流设置为视频元素的源
          videoElement.srcObject = sdk.stream;
          
          // 开始播放
          const session = await sdk.play(streamInfo.url);
          console.log(`单个流播放成功 ${streamInfo.streamId}:`, session);
          
          // 尝试播放视频
          const playPromise = videoElement.play();
          if (playPromise !== undefined) {
            playPromise.catch(error => {
              console.warn('视频播放被阻止:', error);
              videoElement.muted = true;
              videoElement.controls = true;
            });
          }
        } else {
          console.error(`视频元素未找到: remoteVideo_${streamInfo.streamId}`);
        }
      } catch (error) {
        console.error(`创建单个流 ${streamInfo.streamId} 失败:`, error);
      }
    },
    
    // 创建用于观看的RTCPeerConnection
    createPlayerPeerConnection() {
      console.log('开始创建观看用RTCPeerConnection');
      
      // 这里的配置需要根据你的SRS服务器配置进行调整
      const configuration = {
        iceServers: [
          { urls: 'stun:stun.l.google.com:19302' } // 备用公共STUN服务器
        ],
        bundlePolicy: 'max-bundle',  // 确保使用BUNDLE策略
        rtcpMuxPolicy: 'require'     // 确保使用RTCP多路复用
      };
      
      this.playerPeerConnection = new RTCPeerConnection(configuration);
      
      // 当有远程流添加时
      this.playerPeerConnection.ontrack = (event) => {
        console.log('收到远程流:', event);
        // 注意：现在使用SDK播放，不再需要处理MediaStream
      };
      
      // ICE候选处理
      this.playerPeerConnection.onicecandidate = (event) => {
        if (event.candidate && this.signalingConnection) {
          console.log('生成观看用ICE候选');
          
          // 使用Socket.IO的emit方法直接发送
          this.signalingConnection.emit('ice-candidate', {
            candidate: event.candidate,
            roomId: this.roomId
          });
        }
      };
      
      this.playerPeerConnection.onconnectionstatechange = () => {
        console.log('观看连接状态变化:', this.playerPeerConnection.connectionState);
        if (this.playerPeerConnection.connectionState === 'connected') {
          this.publishStatus = `正在观看房间: ${this.roomId}`;
        } else if (this.playerPeerConnection.connectionState === 'failed') {
          this.publishStatus = '观看连接失败';
          // 移除stopPlaying调用
        }
      };
      
      this.playerPeerConnection.oniceconnectionstatechange = () => {
        console.log('观看ICE连接状态变化:', this.playerPeerConnection.iceConnectionState);
        if (this.playerPeerConnection.iceConnectionState === 'failed') {
          this.publishStatus = '观看ICE连接失败';
          // 移除stopPlaying调用
        }
      };
    },
    
    // 处理观看Answer
    async handlePlayerAnswer(data) {
      try {
        console.log('开始处理观看SDP Answer:', {
          hasSdp: !!data.sdp,
          roomId: data.roomId,
          timestamp: new Date().toISOString()
        });
        
        if (this.playerPeerConnection) {
          console.log('设置观看远程描述开始:', {
            timestamp: new Date().toISOString()
          });
          
          await this.playerPeerConnection.setRemoteDescription(
            new RTCSessionDescription({ type: 'answer', sdp: data.sdp })
          );
          
          console.log('成功设置观看远程描述:', {
            timestamp: new Date().toISOString()
          });
        }
      } catch (error) {
        console.error('处理观看Answer时出错:', {
          error: error,
          message: error.message,
          stack: error.stack,
          timestamp: new Date().toISOString()
        });
        this.publishStatus = '处理观看Answer失败: ' + error.message;
      }
    },
    
    // 发起签到
    startAttendance() {
      // if (!this.signalingConnection || !this.roomId) {
      //   uni.showToast({
      //     title: '请先连接信令服务器',
      //     icon: 'none'
      //   });
      //   return;
      // }
      
      if (this.attendanceInProgress) {
        return;
      }
      
      this.attendanceInProgress = true;
      this.attendanceResults = null;
      
      // 发送签到请求
      // this.signalingConnection.emit('start-attendance', {
      //   roomId: this.roomId
      // });
      
      console.log('已发起签到请求');
      // uni.showToast({
      //   title: '签到已发起，等待结果...',
      //   icon: 'none'
      // });

      //打开签到网页在新标签
      window.open(`/attendance?roomId=${this.roomId}&liveTitle=${encodeURIComponent(this.liveTitle)}`, '_blank');

    },
    
    // 处理签到结果
    handleAttendanceResult(data) {
      this.attendanceInProgress = false;
      this.attendanceResults = data;
      
      console.log('收到签到结果:', data);
      
      // 显示签到结果
      const totalUsers = data.totalPlayers;
      const respondedUsers = data.respondedCount;
      const confirmedUsers = data.results.filter(r => r.attended).length;
      
      let resultMessage = `签到结束！\n总用户: ${totalUsers}\n响应用户: ${respondedUsers}\n确认签到: ${confirmedUsers}`;
      
      if (data.results.length > 0) {
        resultMessage += '\n\n详细结果:';
        data.results.forEach(result => {
          resultMessage += `\n${result.playerId}: ${result.attended ? '已签到' : '未确认'}`;
        });
      }
      
      uni.showModal({
        title: '签到结果',
        content: resultMessage,
        showCancel: false,
        confirmText: '确定'
      });
    },
    
    // 获取用户摄像头状态
    getCameraStatus(userId) {
      return this.userCameraStatus.get(userId) || 'enabled'; // 默认为开启状态
    },
    
    // 切换用户摄像头状态
    toggleUserCamera(userId) {
      const currentStatus = this.getCameraStatus(userId);
      const newAction = currentStatus === 'enabled' ? 'disable' : 'enable';
      
      console.log(`播放者请求${newAction === 'enable' ? '开启' : '关闭'}用户 ${userId} 的摄像头`);
      
      // 发送摄像头控制请求到服务器
      this.sendCameraControlRequest(userId, newAction);
    },
    
    // 发送摄像头控制请求
    sendCameraControlRequest(targetUserId, action) {
      if (!this.signalingConnection || !this.signalingConnection.connected) {
        console.error('信令连接未建立，无法发送摄像头控制请求');
        uni.showToast({
          title: '连接未建立',
          icon: 'error'
        });
        return;
      }
      
      const requestData = {
        roomId: this.roomId,
        targetUserId: targetUserId,
        action: action // 'enable' 或 'disable'
      };
      
      // 记录请求状态
      this.cameraControlRequests.set(targetUserId, {
        action: action,
        timestamp: Date.now(),
        status: 'pending'
      });
      
      // 发送Socket.IO事件
      this.signalingConnection.emit('camera-control-request', requestData);
      
      console.log('摄像头控制请求已发送:', requestData);
      
      // 显示加载提示
      uni.showLoading({
        title: `正在${action === 'enable' ? '开启' : '关闭'}摄像头...`
      });
    },
    
    // 处理摄像头控制结果
    handleCameraControlResult(data) {
      const { userId, action, success, error } = data;
      
      console.log('收到摄像头控制结果:', data);
      
      // 隐藏加载提示
      uni.hideLoading();
      
      if (success) {
        // 更新用户摄像头状态
        const newStatus = action === 'enable' ? 'enabled' : 'disabled';
        this.userCameraStatus.set(userId, newStatus);
        
        uni.showToast({
          title: `摄像头已${action === 'enable' ? '开启' : '关闭'}`,
          icon: 'success'
        });
      } else {
        uni.showToast({
          title: `摄像头控制失败: ${error || '未知错误'}`,
          icon: 'error'
        });
      }
      
      // 清除请求记录
      this.cameraControlRequests.delete(userId);
    },
    
    // 处理摄像头控制发送确认
    handleCameraControlSent(data) {
      const { targetUserId, action } = data;
      console.log(`摄像头控制指令已发送给用户 ${targetUserId}，操作: ${action}`);
    },
    
    // 初始化摄像头控制事件监听
    setupCameraControlListeners() {
      if (!this.signalingConnection) {
        console.error('信令连接未建立，无法设置摄像头控制监听器');
        return;
      }
      
      // 监听摄像头控制结果
      this.signalingConnection.on('camera-control-result', (data) => {
        this.handleCameraControlResult(data);
      });
      
      // 监听摄像头控制发送确认
      this.signalingConnection.on('camera-control-sent', (data) => {
        this.handleCameraControlSent(data);
      });
      
      // 监听摄像头状态变化广播
      this.signalingConnection.on('camera-status-changed', (data) => {
        const { userId, action, success } = data;
        if (success) {
          const newStatus = action === 'enable' ? 'enabled' : 'disabled';
          this.userCameraStatus.set(userId, newStatus);
          console.log(`用户 ${userId} 摄像头状态已更新为: ${newStatus}`);
        }
      });
      
      console.log('摄像头控制事件监听器已设置');
    },

    // 添加观众占位符
    addAudiencePlaceholder(userId) {
      // 检查是否已存在该用户的流信息
      const existingStream = this.audienceStreams.find(stream => stream.userId === userId);
      if (existingStream) {
        console.log(`用户 ${userId} 的流信息已存在，跳过添加占位符`);
        return;
      }
      
      // 创建新的流信息对象
      const streamInfo = {
        userId: userId,
        streamId: null,
        hasStream: false, // 标记为占位符状态
        monitoringStatus: 'normal' // 监控状态
      };
      
      this.audienceStreams.push(streamInfo);
      console.log(`为用户 ${userId} 添加观众占位符`);
    },

    // 移除单个观众流
    removeSingleAudienceStream(userId) {
      // 查找流信息
      const streamIndex = this.audienceStreams.findIndex(stream => stream.userId === userId);
      if (streamIndex === -1) {
        console.log(`未找到用户 ${userId} 的流信息`);
        return;
      }
      
      const streamInfo = this.audienceStreams[streamIndex];
      
      // 如果有实际的流，停止SDK
      if (streamInfo.hasStream && this.audienceSdks.has(userId)) {
        try {
          const sdk = this.audienceSdks.get(userId);
          sdk.close();
          this.audienceSdks.delete(userId);
          console.log(`停止用户 ${userId} 的观众流SDK`);
        } catch (error) {
          console.error(`停止用户 ${userId} 的观众流SDK失败:`, error);
        }
      }
      
      // 从数组中移除流信息
      this.audienceStreams.splice(streamIndex, 1);
      console.log(`移除用户 ${userId} 的观众流`);
    },

    // 添加单个观众流
    addSingleAudienceStream(userId, studentName = null, studentId = null) {
      console.log(`添加单个观众流: ${userId}${studentName ? ` (${studentName})` : ''}${studentId ? ` [${studentId}]` : ''}`);
      
      // 检查是否已存在该用户的流信息
      const existingStream = this.audienceStreams.find(stream => stream.userId === userId);
      if (existingStream) {
        // 更新现有流信息
        existingStream.streamId = `${this.roomId}_player_${userId}`;
        existingStream.hasStream = true;
        // 更新studentName和studentId（如果提供了新的）
        if (studentName) {
          existingStream.studentName = studentName;
        }
        if (studentId) {
          existingStream.studentId = studentId;
        }
        console.log(`更新用户 ${userId} 的流信息`);
      } else {
        console.log(`未找到用户 ${userId} 的流信息，可能需要先连接用户`);
        return;
      }
      
      // 播放观众流
      this.playAudienceStream(userId);
    },

    // 播放观众流
    async playAudienceStream(userId) {
      try {
        // 查找流信息
        const streamInfo = this.audienceStreams.find(stream => stream.userId === userId);
        
        console.log(`开始播放观众流，用户: ${userId}, 流ID: ${streamInfo ? streamInfo.streamId : 'unknown'}`);
        if (!streamInfo) {
          console.error(`未找到用户 ${userId} 的流信息`);
          return;
        }
        
        // 确保SDK已加载
        await this.loadSDK();
        console.log('SDK加载完成');
        
        // 创建SDK实例
        const sdk = new SrsRtcWhipWhepAsync();
        console.log('SDK实例创建完成');
        
        // 构建播放URL
        const playUrl = `${this.srsServerUrl}/rtc/v1/whep/?app=live&stream=${streamInfo.streamId}`;
        console.log(`开始播放观众流，URL: ${playUrl}`);
        
        // 获取视频元素
        await this.$nextTick();
        const videoElement = document.getElementById(`audience_video_${userId}`);
        if (!videoElement) {
          console.error(`未找到用户 ${userId} 的视频元素`);
          return;
        }
        console.log(`找到视频元素: audience_video_${userId}`);
        
        // 开始播放
        console.log('开始调用SDK播放方法');
        await sdk.play(playUrl);
        console.log('SDK播放方法调用成功');
        
        videoElement.srcObject = sdk.stream;
        console.log('视频元素srcObject设置完成，使用sdk.stream:', sdk.stream);
        
        // 尝试播放视频
        videoElement.play().catch(error => {
          console.warn(`观众视频播放被阻止 (${userId}):`, error);
        });
        
        // 存储SDK实例
        this.audienceSdks.set(userId, sdk);
        
        console.log(`用户 ${userId} 的观众流播放成功`);
      } catch (error) {
        console.error(`播放用户 ${userId} 的观众流失败:`, error);
      }
    },
    
    // 格式化时间
    formatTime(timestamp) {
      if (!timestamp) return '';
      const date = new Date(timestamp);
      return `${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}`;
    },
    
    // 添加弹幕到列表
    addDanmaku(content, user = '用户', color = '#ffffff') {
      const danmaku = {
        content: content,
        user: user,
        color: color,
        timestamp: Date.now()
      };
      this.danmakuList.push(danmaku);
      
      // 限制弹幕数量，避免过多影响性能
      if (this.danmakuList.length > 100) {
        this.danmakuList.shift();
      }
    },
    
    // 添加测试弹幕
    addTestDanmaku() {
      const testDanmaku = [
        
      ];
      
      testDanmaku.forEach((item, index) => {
        setTimeout(() => {
          this.addDanmaku(item.content, item.user, item.color);
          this.addScrollingDanmaku(item.content, item.user, item.color);
        }, index * 1000);
      });
    },
    
    // 添加滚动弹幕
    addScrollingDanmaku(content, user = '用户', color = '#ffffff') {
      const danmaku = {
        content: content,
        user: user,
        color: color,
        top: Math.floor(Math.random() * 300) + 100, // 随机高度，确保在可见区域
        fontSize: this.getFontSize(),
        timestamp: Date.now(),
        hidden: false
      };
      
      this.scrollingDanmakuList.push(danmaku);
      console.log('添加滚动弹幕:', danmaku.content, '位置:', danmaku.top);
      console.log('当前滚动弹幕列表长度:', this.scrollingDanmakuList.length);
      
      // 限制滚动弹幕数量，避免过多影响性能
      if (this.scrollingDanmakuList.length > 50) {
        this.scrollingDanmakuList.shift();
      }
    },
    
    // 获取字体大小
    getFontSize() {
      const fontSizeMap = {
        small: 12,
        medium: 16,
        large: 20
      };
      return fontSizeMap[this.selectedSize] || 16;
    },
    
    // 获取弹幕样式
    getDanmakuStyle(item, index) {
      return {
        color: item.color || '#ffffff',
        fontSize: (item.fontSize || this.getFontSize()) + 'px',
        top: (item.top || Math.floor(Math.random() * 300) + 100) + 'rpx',
        left: '100%' // 从右侧开始
      };
    },
    
    // 处理弹幕动画结束
    handleDanmakuEnd(item) {
      try {
        item.hidden = true;
      } catch (e) {
        console.error('隐藏弹幕失败', e);
      }
    },
    
    // 切换弹幕开关
    toggleDanmaku() {
      this.isDanmakuEnabled = !this.isDanmakuEnabled;
    },
    
    // 发送消息
    sendMessage() {
      if (!this.inputMessage.trim()) {
        // 使用原生提示替代uni.showToast
        console.warn('请输入弹幕内容');
        alert('请输入弹幕内容');
        return;
      }
      
      // 优先使用WebSocket发送
      if (this.isDanmakuEnabled && this.websocketTask && this.websocketConnected) {
        const danmakuMessage = {
          type: 'danmaku',
          content: this.inputMessage,
          user: getUserRealName() || '匿名用户',
          toUserid: '103',
          timestamp: Date.now()
        };

        // 通过WebSocket发送弹幕
        this.websocketTask.send(JSON.stringify(danmakuMessage));
        console.log('弹幕已通过WebSocket发送:', danmakuMessage);
        
        // 同时本地显示
       
      } else {
        // WebSocket不可用时，本地发送
        this.addDanmaku(this.inputMessage, '我', this.selectedColor);
        this.addScrollingDanmaku(this.inputMessage, '我', this.selectedColor);
        console.log('弹幕已本地发送:', this.inputMessage);
      }
      
      // 清空输入框
      this.inputMessage = '';
      
      // 显示发送成功提示
      console.log('弹幕发送成功');
    },
    
    // 连接WebSocket
    connectWebSocket() {
      try {
        const classId = this.roomId; // 使用从URL获取的动态班级ID
        const wsUrl = `ws://localhost:9006/danmaku-ws?classId=${classId}`;
        
        this.websocketTask = new WebSocket(wsUrl);
        console.log('WebSocket连接请求已发送（班级ID: ' + classId + '）');

        // 监听WebSocket连接打开事件
        this.websocketTask.onopen = () => {
          console.log('WebSocket连接已打开');
          this.websocketConnected = true;
        };

        // 监听WebSocket消息接收事件
        this.websocketTask.onmessage = (event) => {
          try {
            let data = event.data;
            console.log('收到WebSocket消息:', event.data);
            
            // 检查是否是服务器回复的消息格式
            if (typeof data === 'string' && data.startsWith('服务器回复: ')) {
              const jsonStr = data.substring('服务器回复: '.length);
              data = JSON.parse(jsonStr);
            } else if (typeof data === 'string') {
              data = JSON.parse(data);
            }

            // 添加消息去重逻辑
            const isDuplicate = this.danmakuList.some(item =>
              item.timestamp === data.timestamp &&
              item.content === data.content
            );

            if (isDuplicate) {
              console.log('过滤重复消息:', data);
              return;
            }

            // 处理不同类型的WebSocket消息
            if (data.type === 'danmaku') {
              const danmakuItem = {
                content: data.content,
                top: Math.floor(Math.random() * 400) + 50,
                color: data.color || '#ffffff',
                fontSize: data.fontSize || this.getFontSize(),
                user: data.user || data.userName,
                position: data.position || 'full',
                timestamp: data.timestamp || Date.now()
              };

              if (danmakuItem.content && danmakuItem.content.trim()) {
                // 添加到历史弹幕列表
                this.addDanmaku(danmakuItem.content, danmakuItem.user, danmakuItem.color);
                // 添加到滚动弹幕列表
                this.addScrollingDanmaku(danmakuItem.content, danmakuItem.user, danmakuItem.color);
                console.log('WebSocket弹幕已添加:', danmakuItem.content);
              }
            }
            // 处理AI助手回复
            else if (data.type === 'ai_reply') {
              const aiDanmaku = {
                content: data.content,
                top: Math.floor(Math.random() * 400) + 50,
                color: '#00ff00', // AI回复使用绿色
                fontSize: this.getFontSize(),
                position: data.position || this.danmakuPosition,
                user: 'AI助手',
                timestamp: data.timestamp || Date.now()
              };

              if (aiDanmaku.content && aiDanmaku.content.trim()) {
                this.addDanmaku(aiDanmaku.content, aiDanmaku.user, aiDanmaku.color);
                this.addScrollingDanmaku(aiDanmaku.content, aiDanmaku.user, aiDanmaku.color);
              }
            }
          } catch (e) {
            // 如果不是JSON格式，则作为普通文本处理
            console.log('收到WebSocket文本消息:', event.data);

            const isDuplicate = this.danmakuList.some(item =>
              item.content === event.data &&
              (Date.now() - (item.timestamp || 0)) < 1000
            );

            if (isDuplicate) {
              console.log('过滤重复文本消息:', event.data);
              return;
            }

            const danmakuItem = {
              content: event.data,
              top: Math.floor(Math.random() * 400) + 50,
              color: '#ffffff',
              fontSize: this.getFontSize(),
              user: '系统',
              position: 'full',
              timestamp: Date.now()
            };

            if (danmakuItem.content && danmakuItem.content.trim()) {
              this.addDanmaku(danmakuItem.content, danmakuItem.user, danmakuItem.color);
              this.addScrollingDanmaku(danmakuItem.content, danmakuItem.user, danmakuItem.color);
            }
          }
        };

        // 监听WebSocket关闭事件
        this.websocketTask.onclose = () => {
          console.log('WebSocket连接已关闭');
          this.websocketConnected = false;
        };

        // 监听WebSocket错误事件
        this.websocketTask.onerror = (err) => {
          console.error('WebSocket错误:', err);
          this.websocketConnected = false;
        };
      } catch (error) {
        console.error('WebSocket连接初始化失败:', error);
      }
    },
    
    // 测试弹幕方法
    testDanmaku() {
      const testMessages = ['测试弹幕1', '666666', '主播加油！', '学到了', '支持支持！'];
      const randomMessage = testMessages[Math.floor(Math.random() * testMessages.length)];
      
      this.addDanmaku(randomMessage, '测试用户', this.selectedColor);
      this.addScrollingDanmaku(randomMessage, '测试用户', this.selectedColor);
      
      console.log('测试弹幕已发送');
    },

    
    // 切换全屏状态
    toggleFullscreen() {
      this.isFullscreen = !this.isFullscreen;
      
      if (this.isFullscreen) {
        // 进入全屏
        this.enterFullscreen();
      } else {
        // 退出全屏
        this.exitFullscreen();
      }
    },
    
    // 进入全屏
    enterFullscreen() {
      try {
        const videoContainer = document.querySelector('.main-video-wrapper');
        if (videoContainer) {
          if (videoContainer.requestFullscreen) {
            videoContainer.requestFullscreen();
          } else if (videoContainer.webkitRequestFullscreen) {
            videoContainer.webkitRequestFullscreen();
          } else if (videoContainer.mozRequestFullScreen) {
            videoContainer.mozRequestFullScreen();
          } else if (videoContainer.msRequestFullscreen) {
            videoContainer.msRequestFullscreen();
          }
          
          // 全屏后调整视频尺寸
          this.$nextTick(() => {
            this.adjustVideoForFullscreen();
          });
        }
      } catch (error) {
        console.error('进入全屏失败:', error);
        // 如果浏览器全屏失败，使用自定义全屏
        this.isFullscreen = true;
        this.adjustVideoForFullscreen();
      }
    },
    
    // 退出全屏
    exitFullscreen() {
      try {
        if (document.exitFullscreen) {
          document.exitFullscreen();
        } else if (document.webkitExitFullscreen) {
          document.webkitExitFullscreen();
        } else if (document.mozCancelFullScreen) {
          document.mozCancelFullScreen();
        } else if (document.msExitFullscreen) {
          document.msExitFullscreen();
        }
      } catch (error) {
        console.error('退出全屏失败:', error);
        // 如果浏览器全屏失败，使用自定义全屏
        this.isFullscreen = false;
      }
    },
    
    // 设置全屏状态监听
    setupFullscreenListeners() {
      // 监听全屏状态变化
      const fullscreenChangeEvents = [
        'fullscreenchange',
        'webkitfullscreenchange',
        'mozfullscreenchange',
        'MSFullscreenChange'
      ];
      
      fullscreenChangeEvents.forEach(event => {
        document.addEventListener(event, () => {
          this.handleFullscreenChange();
        });
      });
    },
    
    // 处理全屏状态变化
    handleFullscreenChange() {
      const isCurrentlyFullscreen = !!(
        document.fullscreenElement ||
        document.webkitFullscreenElement ||
        document.mozFullScreenElement ||
        document.msFullscreenElement
      );
      
      this.isFullscreen = isCurrentlyFullscreen;
      console.log('全屏状态变化:', this.isFullscreen);
      
      // 全屏状态变化时调整视频尺寸
      if (this.isFullscreen) {
        this.$nextTick(() => {
          this.adjustVideoForFullscreen();
        });
      } else {
        this.$nextTick(() => {
          this.resetVideoSize();
        });
      }
    },
    
    // 调整视频为全屏尺寸
    adjustVideoForFullscreen() {
      const videoElement = document.getElementById('localVideo');
      if (videoElement) {
        videoElement.style.width = '100vw';
        videoElement.style.height = '100vh';
        videoElement.style.objectFit = 'cover';
        videoElement.style.position = 'fixed';
        videoElement.style.top = '0';
        videoElement.style.left = '0';
        videoElement.style.zIndex = '999';
        videoElement.style.transform = 'scaleX(-1)';
      }
    },
    
    // 重置视频尺寸
    resetVideoSize() {
      const videoElement = document.getElementById('localVideo');
      if (videoElement) {
        videoElement.style.width = '100%';
        videoElement.style.height = '75%';
        videoElement.style.objectFit = 'fill';
        videoElement.style.position = 'relative';
        videoElement.style.top = 'auto';
        videoElement.style.left = 'auto';
        videoElement.style.zIndex = 'auto';
        videoElement.style.transform = 'scaleX(-1)';
      }
    },
    
    // ==================== 设备控制功能 ====================
    
    // 切换学生摄像头
    toggleStudentCamera(userId, studentId) {
      console.log('=== 摄像头控制按钮被点击 ===');
      console.log('用户ID:', userId);
      console.log('学生ID:', studentId);
      console.log('设备控制功能状态:', this.deviceControlEnabled);
      console.log('信令连接状态:', this.signalingConnection ? '已连接' : '未连接');
      
      if (!this.deviceControlEnabled) {
        console.log('设备控制功能已禁用');
        return;
      }
      
      const stream = this.audienceStreams.find(s => s.userId === userId);
      if (!stream) {
        console.error(`未找到用户 ${userId} 的流信息`);
        console.log('当前观众流列表:', this.audienceStreams);
        return;
      }
      
      // 切换摄像头状态
      stream.cameraEnabled = !stream.cameraEnabled;
      
      // 如果重新开启摄像头，需要重新播放流
      if (stream.cameraEnabled && stream.hasStream) {
        console.log('重新开启摄像头，重新播放流');
        this.$nextTick(() => {
          this.playAudienceStream(userId);
        });
      }
      
      // 发送控制指令到学生端
      this.sendDeviceControlCommand(userId, studentId, 'camera', stream.cameraEnabled);
      
      console.log(`切换学生 ${stream.studentName} 摄像头: ${stream.cameraEnabled ? '开启' : '关闭'}`);
    },
    
    // 切换学生麦克风
    toggleStudentMicrophone(userId, studentId) {
      if (!this.deviceControlEnabled) {
        console.log('设备控制功能已禁用');
        return;
      }
      
      const stream = this.audienceStreams.find(s => s.userId === userId);
      if (!stream) {
        console.error(`未找到用户 ${userId} 的流信息`);
        return;
      }
      
      // 切换麦克风状态
      stream.micEnabled = !stream.micEnabled;
      
      // 发送控制指令到学生端
      this.sendDeviceControlCommand(userId, studentId, 'microphone', stream.micEnabled);
      
      console.log(`切换学生 ${stream.studentName} 麦克风: ${stream.micEnabled ? '开启' : '关闭'}`);
    },
    
    // 发送设备控制指令
    sendDeviceControlCommand(userId, studentId, deviceType, enabled) {
      console.log('=== 设备控制调试信息 ===');
      console.log('信令连接状态:', this.signalingConnection ? '已连接' : '未连接');
      console.log('信令连接ID:', this.signalingConnection ? this.signalingConnection.id : '无');
      console.log('目标用户ID:', userId);
      console.log('学生ID:', studentId);
      console.log('设备类型:', deviceType);
      console.log('启用状态:', enabled);
      
      if (!this.signalingConnection) {
        console.error('信令服务器未连接');
        return;
      }
      
      if (!this.signalingConnection.connected) {
        console.error('信令服务器连接已断开');
        return;
      }
      
      const command = {
        targetUserId: userId,
        studentId: studentId,
        deviceType: deviceType, // 'camera' 或 'microphone'
        enabled: enabled,
        timestamp: new Date().toISOString()
      };
      
      console.log('准备发送设备控制指令:', command);
      this.signalingConnection.emit('device-control', command);
      console.log('设备控制指令已发送');
    },
    
    // 批量控制所有学生设备
    controlAllStudentsDevices(deviceType, enabled) {
      if (!this.deviceControlEnabled) {
        console.log('设备控制功能已禁用');
        return;
      }
      
      const activeStreams = this.audienceStreams.filter(stream => 
        stream.hasStream && !stream.isPlaceholder
      );
      
      activeStreams.forEach(stream => {
        if (deviceType === 'camera') {
          stream.cameraEnabled = enabled;
        } else if (deviceType === 'microphone') {
          stream.micEnabled = enabled;
        }
        
        this.sendDeviceControlCommand(stream.userId, stream.studentId, deviceType, enabled);
      });
      
      console.log(`批量${enabled ? '开启' : '关闭'}所有学生${deviceType === 'camera' ? '摄像头' : '麦克风'}`);
    },
    
    // ==================== 推流监控记录系统 ====================
    
    // 开始推流会话监控
    startStreamingSession() {
      this.streamingSessionActive = true;
      this.streamingStartTime = new Date();
      this.streamingEndTime = null;
      
      // 清空之前的记录
      this.studentMonitoringStats.clear();
      this.sessionMonitoringLog = [];
      this.sessionStreamLog = [];
      
      // 初始化所有学生的统计数据
      this.studentList.forEach((studentName, index) => {
        const studentId = `student_${index + 1}`;
        this.studentMonitoringStats.set(studentId, {
          monitoringSuccess: 0,
          monitoringFailed: 0,
          streamConnected: 0,
          streamDisconnected: 0,
          studentName: studentName,
          studentId: studentId
        });
      });
      
      // 为已连接的用户初始化统计数据
      this.connectedUsers.forEach(user => {
        const studentId = user.studentId || user.userId;
        const studentName = user.studentName || user.userId;
        if (!this.studentMonitoringStats.has(studentId)) {
          this.studentMonitoringStats.set(studentId, {
            monitoringSuccess: 0,
            monitoringFailed: 0,
            streamConnected: 0,
            streamDisconnected: 0,
            studentName: studentName,
            studentId: studentId
          });
        }
      });
      
      console.log('推流监控记录系统已启动', {
        startTime: this.streamingStartTime,
        initialStudents: this.studentMonitoringStats.size
      });
      
      // 自动开启监控
      // if (!this.monitoringEnabled) {
      //   this.toggleMonitoring();
      // }
    },
    
    // 结束推流会话监控
    endStreamingSession() {
      if (!this.streamingSessionActive) {
        return;
      }
      
      this.streamingSessionActive = false;
      this.streamingEndTime = new Date();
      
      console.log('推流监控记录系统已结束', {
        endTime: this.streamingEndTime,
        duration: this.streamingEndTime - this.streamingStartTime
      });
      
      // 显示统计弹窗
      this.showStreamingSessionSummary();
    },
    
    // 记录监控结果
    recordMonitoringResult(studentId, studentName, isSuccess) {
      if (!this.streamingSessionActive) {
        return;
      }
      
      // 确保学生存在于统计中
      if (!this.studentMonitoringStats.has(studentId)) {
        this.studentMonitoringStats.set(studentId, {
          monitoringSuccess: 0,
          monitoringFailed: 0,
          streamConnected: 0,
          streamDisconnected: 0,
          studentName: studentName || '未知学生',
          studentId: studentId
        });
      }
      
      const stats = this.studentMonitoringStats.get(studentId);
      if (isSuccess) {
        stats.monitoringSuccess++;
        // 更新观众流的监控状态为正常
        this.updateStreamMonitoringStatus(studentId, 'normal');
      } else {
        stats.monitoringFailed++;
        // 更新观众流的监控状态为暂离
        this.updateStreamMonitoringStatus(studentId, 'away');
      }
      
      // 记录到监控日志
      this.sessionMonitoringLog.push({
        studentId: studentId,
        studentName: studentName || '未知学生',
        timestamp: new Date(),
        result: isSuccess ? 'success' : 'failed',
        type: 'monitoring'
      });
      
      console.log(`记录监控结果: ${studentName || studentId} - ${isSuccess ? '成功' : '失败'}`);
    },
    
    // 更新观众流的监控状态
    updateStreamMonitoringStatus(studentId, status) {
      const stream = this.audienceStreams.find(s => s.studentId === studentId);
      if (stream) {
        stream.monitoringStatus = status;
        console.log(`更新学生 ${stream.studentName || studentId} 监控状态为: ${status}`);
      }
    },
    
    // 获取显示名称（包含监控状态）
    getDisplayName(stream) {
      const baseName = stream.studentName || stream.userId;
      if (stream.monitoringStatus === 'away') {
        return `${baseName}（暂离）`;
      }
      return baseName;
    },
    
    // 获取监控状态对应的CSS类
    getMonitoringStatusClass(stream) {
      if (stream.monitoringStatus === 'away') {
        return 'away-label';
      } else if (stream.monitoringStatus === 'offline') {
        return 'offline-label';
      }
      return 'online-label';
    },
    
    // 记录流连接状态
    recordStreamConnection(studentId, studentName, isConnected) {
      if (!this.streamingSessionActive) {
        return;
      }
      
      // 确保学生存在于统计中
      if (!this.studentMonitoringStats.has(studentId)) {
        this.studentMonitoringStats.set(studentId, {
          monitoringSuccess: 0,
          monitoringFailed: 0,
          streamConnected: 0,
          streamDisconnected: 0,
          studentName: studentName || '未知学生',
          studentId: studentId
        });
      }
      
      const stats = this.studentMonitoringStats.get(studentId);
      if (isConnected) {
        stats.streamConnected++;
      } else {
        stats.streamDisconnected++;
      }
      
      // 记录到流连接日志
      this.sessionStreamLog.push({
        studentId: studentId,
        studentName: studentName || '未知学生',
        timestamp: new Date(),
        action: isConnected ? 'connected' : 'disconnected',
        type: 'stream'
      });
      
      console.log(`记录流连接状态: ${studentName || studentId} - ${isConnected ? '连接' : '断开'}`);
    },
    
    // 根据用户ID获取学生姓名
    getStudentNameByUserId(userId) {
      // 先从audienceStreams中查找
      const stream = this.audienceStreams.find(s => s.userId === userId);
      if (stream && stream.studentName) {
        return stream.studentName;
      }
      
      // 从connectedUsers中查找
      const user = this.connectedUsers.find(u => u.userId === userId);
      if (user && user.studentName) {
        return user.studentName;
      }
      
      // 如果是student_开头的ID，尝试从studentList中获取
      if (userId.startsWith('student_')) {
        const index = parseInt(userId.replace('student_', '')) - 1;
        if (index >= 0 && index < this.studentList.length) {
          return this.studentList[index];
        }
      }
      
      // 默认返回用户ID
      return userId;
    },
    
    // 显示推流会话统计弹窗
    showStreamingSessionSummary() {
      const duration = this.streamingEndTime - this.streamingStartTime;
      const durationMinutes = Math.floor(duration / 60000);
      const durationSeconds = Math.floor((duration % 60000) / 1000);
      
      // 计算总体统计
      let totalMonitoringSuccess = 0;
      let totalMonitoringFailed = 0;
      let totalStreamConnected = 0;
      let totalStreamDisconnected = 0;
      let activeStudents = 0;
      
      const studentStats = [];
      
      this.studentMonitoringStats.forEach((stats, studentId) => {
        const hasActivity = stats.monitoringSuccess > 0 || stats.monitoringFailed > 0 || 
                           stats.streamConnected > 0 || stats.streamDisconnected > 0;
        
        if (hasActivity) {
          activeStudents++;
          totalMonitoringSuccess += stats.monitoringSuccess;
          totalMonitoringFailed += stats.monitoringFailed;
          totalStreamConnected += stats.streamConnected;
          totalStreamDisconnected += stats.streamDisconnected;
          
          studentStats.push({
            studentId: studentId,
            studentName: stats.studentName,
            ...stats
          });
        }
      });
      
      // 按活跃度排序（监控次数 + 连接次数）
      studentStats.sort((a, b) => {
        const aActivity = a.monitoringSuccess + a.monitoringFailed + a.streamConnected + a.streamDisconnected;
        const bActivity = b.monitoringSuccess + b.monitoringFailed + b.streamConnected + b.streamDisconnected;
        return bActivity - aActivity;
      });
      
      // 构建弹窗内容
      let summaryContent = `推流会话统计报告\n\n`;
      summaryContent += `📅 会话时间: ${this.streamingStartTime.toLocaleString()} - ${this.streamingEndTime.toLocaleString()}\n`;
      summaryContent += `⏱️ 持续时长: ${durationMinutes}分${durationSeconds}秒\n\n`;
      
      summaryContent += `📊 总体统计:\n`;
      summaryContent += `👥 活跃学生: ${activeStudents}人\n`;
      summaryContent += `✅ 监控成功: ${totalMonitoringSuccess}次\n`;
      summaryContent += `❌ 监控失败: ${totalMonitoringFailed}次\n`;
      summaryContent += `🔗 流连接: ${totalStreamConnected}次\n`;
      summaryContent += `🔌 流断开: ${totalStreamDisconnected}次\n\n`;
      
      if (studentStats.length > 0) {
        summaryContent += `👨‍🎓 学生详细统计 (前10名):\n`;
        studentStats.slice(0, 10).forEach((student, index) => {
          summaryContent += `${index + 1}. ${student.studentName}\n`;
          summaryContent += `   监控: ✅${student.monitoringSuccess} ❌${student.monitoringFailed}\n`;
          summaryContent += `   流状态: 🔗${student.streamConnected} 🔌${student.streamDisconnected}\n`;
        });
      }
      
      // 显示弹窗
      if (typeof uni !== 'undefined') {
        // uni-app环境
        uni.showModal({
          title: '推流会话统计',
          content: summaryContent,
          showCancel: false,
          confirmText: '确定'
        });
      } else {
        // 浏览器环境
        alert(summaryContent);
      }
      
      console.log('推流会话统计:', {
        duration: `${durationMinutes}:${durationSeconds}`,
        activeStudents,
        totalMonitoringSuccess,
        totalMonitoringFailed,
        totalStreamConnected,
        totalStreamDisconnected,
        studentStats
      });
    },
    
    // ==================== 监控功能 ====================
    
    // 切换监控状态
    toggleMonitoring() {
      if (this.monitoringEnabled) {
        this.monitoringEnabled = false;
        this.stopMonitoring();
        console.log('监控已关闭');
      } else {
        this.monitoringEnabled = true;
        this.startMonitoring();
        console.log('监控已开启');
      }
    },
    
    // 启动监控
    startMonitoring() {
      if (!this.monitoringEnabled || this.monitoringInterval) {
        return;
      }
      
      console.log('启动学生在线监控，间隔时间:', this.monitoringIntervalTime / 1000, '秒');
      
      // 立即执行一次监控
      this.performMonitoring();
      
      // 设置定时器
      this.monitoringInterval = setInterval(() => {
        this.performMonitoring();
      }, this.monitoringIntervalTime);
    },
    
    // 停止监控
    stopMonitoring() {
      if (this.monitoringInterval) {
        clearInterval(this.monitoringInterval);
        this.monitoringInterval = null;
        console.log('学生在线监控已停止');
      }
    },
    
    // 执行监控
    performMonitoring() {
      console.log('执行学生在线监控检查...');
      
      // 遍历所有有流播放的学生
      this.audienceStreams.forEach(stream => {
        if (!stream.isPlaceholder && stream.userId && stream.studentId) {
          this.captureStudentScreenshot(stream);
        }
      });
    },
    
    // 截取学生视频截图
    captureStudentScreenshot(stream) {
      const { userId, studentId, studentName } = stream;
      
      try {
        const videoElement = document.getElementById(`audience_video_${userId}`);
        if (!videoElement || videoElement.videoWidth === 0 || videoElement.videoHeight === 0) {
          console.warn(`学生 ${studentName || studentId} (${userId}) 的视频元素不可用或未加载`);
          return;
        }
        
        // 创建canvas进行截图
        const canvas = document.createElement('canvas');
        const ctx = canvas.getContext('2d');
        
        canvas.width = videoElement.videoWidth;
        canvas.height = videoElement.videoHeight;
        
        // 绘制视频帧到canvas
        ctx.drawImage(videoElement, 0, 0, canvas.width, canvas.height);
        
        // 获取图像数据
        const imageData = canvas.toDataURL('image/jpeg', 0.8);
        //打印图像数据
        
        // 调用监控接口
        this.callMonitorFacesAPI(studentId, studentName, imageData);
        
      } catch (error) {
        console.error(`截取用户 ${userId} 截图失败:`, error);
      }
    },
    
    // 调用监控接口
    async callMonitorFacesAPI(studentId, studentName, imageData) {
      try {
        // 将base64转换为Blob
        const response = await fetch(imageData);
        const blob = await response.blob();
        
        // 创建File对象
        const imageFile = new File([blob], `${studentId}_${Date.now()}.jpg`, {
          type: 'image/jpeg'
        });
        
        // 调用监控接口
        const result = await monitorFace(studentId, imageFile);
        
        if (result && result.code === 200) {
          console.log(`学生 ${studentName || studentId} 监控成功:`, result);
          this.recordMonitoringResult(studentId, studentName, true);
        } else {
          console.log(`学生 ${studentName || studentId} 监控失败:`, result);
          this.recordMonitoringResult(studentId, studentName, false);
        }
        
      } catch (error) {
        console.error(`调用监控接口失败 (${studentName || studentId}):`, error);
        this.recordMonitoringResult(studentId, studentName, false);
      }
    }
  },

  beforeDestroy() {
    // 停止学生在线监控
    this.stopMonitoring();
    
    // 关闭之前的连接
    if (this.sdk) {
      this.sdk.close();
      this.sdk = null;
    }
    
    // 清理观众流资源
    this.audienceSdks.forEach((sdk, userId) => {
      try {
        sdk.close();
        console.log(`清理用户 ${userId} 的观众流SDK`);
      } catch (error) {
        console.error(`清理用户 ${userId} 的观众流SDK失败:`, error);
      }
    });
    this.audienceSdks.clear();
    this.audienceStreams = [];
    
    // 关闭WebSocket连接
    if (this.websocketTask) {
      this.websocketTask.close();
      console.log('WebSocket连接已关闭');
    }
    
    // 组件销毁前停止所有媒体流
    this.stopStream();
    // 停止推流
    this.stopPublishing();
    // 停止观看
    // 移除stopPlaying调用
  },
  

}
</script>

<style scoped>
.container {
  display: flex;
  flex-direction: column;
  height: 140vh;
  width: 100vw;
  max-width: none;
  margin: 0;
  padding: 0;
  background: linear-gradient(135deg, #0f1419 0%, #1a1f29 50%, #0f1419 100%);
  color: #ffffff;
  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
  box-sizing: border-box;
}

.header {
  text-align: center;
  padding: 20px 0;
  background: linear-gradient(90deg, #1e3a8a 0%, #3b82f6 50%, #1e3a8a 100%);
  border-bottom: 2px solid rgba(59, 130, 246, 0.3);
  box-shadow: 0 4px 20px rgba(59, 130, 246, 0.1);
  position: relative;
  overflow: hidden;
}

.header::before {
  content: '';
  position: absolute;
  top: 0;
  left: -100%;
  width: 100%;
  height: 100%;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,0.1), transparent);
  animation: shimmer 3s infinite;
}

@keyframes shimmer {
  0% { left: -100%; }
  100% { left: 100%; }
}

.title {
  font-size: 18px;
  font-weight: 600;
  color: #ffffff;
  text-shadow: 0 2px 10px rgba(59, 130, 246, 0.5);
  letter-spacing: 1px;
  position: relative;
  z-index: 1;
}

.main-content {
  flex: 1;
  display: flex;
  flex-direction: row;
  background: transparent;
  overflow: hidden;
  gap: 20px;
  padding: 15px 20px;
  width: 100%;
  box-sizing: border-box;
}

.main-video-section, .audience-video-section, .danmaku-list-section {
  display: flex;
  flex-direction: column;
  height: 100%;
  border-radius: 16px;
  backdrop-filter: blur(10px);
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid rgba(255, 255, 255, 0.1);
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
  transition: all 0.3s ease;
}

.main-video-section {
  flex: 1.5;
  padding: 15px;
  box-sizing: border-box;
}

.main-video-section:hover {
  transform: translateY(-2px);
  box-shadow: 0 12px 40px rgba(59, 130, 246, 0.2);
}

.audience-video-section {
  flex: 4.5;
  padding: 15px;
  box-sizing: border-box;
}

.audience-video-section:hover {
  transform: translateY(-2px);
  box-shadow: 0 12px 40px rgba(168, 85, 247, 0.2);
}

.danmaku-list-section {
  flex: 1;
  padding: 20px;
  box-sizing: border-box;
}

.danmaku-list-section:hover {
  transform: translateY(-2px);
  box-shadow: 0 12px 40px rgba(34, 197, 94, 0.2);
}

.section-title {
  color: #fff;
  font-size: 14px;
  font-weight: 600;
  padding: 15px 0;
  text-align: center;
  background: linear-gradient(135deg, rgba(59, 130, 246, 0.2), rgba(147, 51, 234, 0.2));
  border-radius: 12px;
  margin-bottom: 20px;
  border: 1px solid rgba(255, 255, 255, 0.1);
  backdrop-filter: blur(5px);
  text-shadow: 0 2px 8px rgba(0, 0, 0, 0.5);
  position: relative;
  overflow: hidden;
}

.section-title::before {
  content: '';
  position: absolute;
  top: 0;
  left: -100%;
  width: 100%;
  height: 2px;
  background: linear-gradient(90deg, transparent, #3b82f6, transparent);
  animation: titleGlow 2s infinite;
}

@keyframes titleGlow {
  0% { left: -100%; }
  100% { left: 100%; }
}

.main-video-wrapper, .audience-video-wrapper, .danmaku-list-wrapper {
  flex: 1;
  overflow: hidden;
  position: relative;
}

.main-video-wrapper {
  height: calc(100% - 100rpx);
}

.audience-video-wrapper {
  overflow-y: auto;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  grid-gap: 12px;
  padding: 15px;
  max-height: 100%;
}

.danmaku-list-wrapper {
  overflow-y: auto;
  background: linear-gradient(135deg, rgba(34, 197, 94, 0.1), rgba(16, 185, 129, 0.1));
  border-radius: 16px;
  padding: 20px;
  border: 1px solid rgba(34, 197, 94, 0.2);
  backdrop-filter: blur(5px);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1);
}

.main-video-container, .remote-video-container {
  position: relative;
  width: 100%;
  height: 100%;
  margin-bottom: 20px;
  border: 2px solid rgba(59, 130, 246, 0.3);
  border-radius: 16px;
  overflow: hidden;
  background: linear-gradient(135deg, #000 0%, #1a1a2e 50%, #000 100%);
  box-shadow: 
    0 8px 32px rgba(0, 0, 0, 0.4),
    inset 0 1px 0 rgba(255, 255, 255, 0.1);
  transition: all 0.3s ease;
}

.main-video-container:hover {
  border-color: rgba(59, 130, 246, 0.6);
  box-shadow: 
    0 12px 40px rgba(59, 130, 246, 0.3),
    inset 0 1px 0 rgba(255, 255, 255, 0.2);
  transform: scale(1.02);
}

.remote-video-container {
  height: 120px;
  margin-bottom: 0;
  position: relative;
  aspect-ratio: 16/9;
  min-height: 90px;
}

.video-container {
  position: relative;
  width: 100%;
  height: 100%;
  border-radius: 16px;
  overflow: hidden;
}

/* 摄像头控制按钮样式 */
.camera-control-overlay {
  position: absolute;
  top: 10rpx;
  right: 10rpx;
  z-index: 10;
}

.camera-control-btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  width: 40rpx;
  height: 40rpx;
  background-color: rgba(0, 0, 0, 0.7);
  border: none;
  border-radius: 50%;
  color: white;
  font-size: 16rpx;
  transition: all 0.3s ease;
}

.camera-control-btn:hover {
  background-color: rgba(0, 0, 0, 0.9);
  transform: scale(1.1);
}

.camera-control-btn.camera-disabled {
  background-color: rgba(255, 0, 0, 0.7);
}

.camera-control-btn.camera-disabled:hover {
  background-color: rgba(255, 0, 0, 0.9);
}

.camera-icon {
  font-size: 20rpx;
  margin-bottom: 2rpx;
}

.camera-text {
  font-size: 12rpx;
  line-height: 1;
}

.video-label {
  position: absolute;
  top: 4px;
  left: 4px;
  background-color: rgba(0,0,0,0.5);
  color: white;
  padding: 2px 6px;
  border-radius: 6px;
  font-size: 9px;
  display: flex;
  align-items: center;
  gap: 4px;
  max-width: calc(100% - 12px);
  box-sizing: border-box;
  font-weight: 400;
  line-height: 1.2;
}

/* 视频覆盖标签样式 */
.video-overlay-label {
  position: absolute;
  top: 4px;
  left: 4px;
  background: linear-gradient(135deg, rgba(0, 0, 0, 0.7), rgba(0, 0, 0, 0.5));
  color: white;
  padding: 2px 6px;
  border-radius: 6px;
  font-size: 9px;
  display: flex;
  align-items: center;
  gap: 4px;
  max-width: calc(100% - 12px);
  box-sizing: border-box;
  backdrop-filter: blur(5px);
  border: 1px solid rgba(255, 255, 255, 0.15);
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2);
  z-index: 10;
  font-weight: 400;
  text-shadow: 0 1px 1px rgba(0, 0, 0, 0.8);
  line-height: 1.2;
}

.video-overlay-label.online-label {
  background: linear-gradient(135deg, rgba(34, 197, 94, 0.8), rgba(21, 128, 61, 0.7));
  border: 1px solid rgba(34, 197, 94, 0.4);
  font-size: 8px;
}

.video-overlay-label.away-label {
  background: linear-gradient(135deg, rgba(251, 191, 36, 0.8), rgba(245, 158, 11, 0.7));
  border: 1px solid rgba(251, 191, 36, 0.4);
  font-size: 8px;
  color: #92400e;
}

/* 设备控制按钮样式 */
.device-controls {
  position: absolute;
  top: 8px;
  right: 8px;
  display: flex;
  gap: 4px;
  z-index: 10;
}

.control-icon-btn {
  width: 32px;
  height: 32px;
  border: none;
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.6);
  color: white;
  font-size: 14px;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.3s ease;
}

.control-icon-btn:hover {
  background: rgba(0, 0, 0, 0.8);
  transform: scale(1.1);
}

.control-icon-btn.disabled {
  background: rgba(255, 0, 0, 0.6);
  opacity: 0.7;
}

.camera-btn {
  background: rgba(0, 150, 0, 0.6);
}

.camera-btn.disabled {
  background: rgba(255, 0, 0, 0.6);
}

.mic-btn {
  background: rgba(0, 100, 255, 0.6);
}

.mic-btn.disabled {
  background: rgba(255, 0, 0, 0.6);
}

/* 批量控制按钮样式 */
.device-control-btn {
  background: #4CAF50;
  color: white;
  border: none;
  padding: 8px 12px;
  margin: 2px;
  border-radius: 4px;
  cursor: pointer;
  font-size: 12px;
  transition: background-color 0.3s;
}

.device-control-btn:hover {
  background: #45a049;
}

.device-control-btn:disabled {
  background: #cccccc;
  cursor: not-allowed;
}

/* 摄像头关闭占位符样式 */
.camera-disabled-placeholder {
  width: 100%;
  height: 100%;
  background: #000;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  color: #fff;
  border-radius: 8px;
  position: relative;
}

.camera-disabled-placeholder .placeholder-icon {
  font-size: 48px;
  margin-bottom: 10px;
  opacity: 0.7;
}

.camera-disabled-placeholder .placeholder-text {
  font-size: 14px;
  opacity: 0.8;
}

.local-label {
  background-color: rgba(0,122,255,0.7);
}

.remote-label {
  background-color: rgba(255,149,0,0.7);
}

/* 离线状态的标签样式 */
.offline-label {
  background-color: rgba(239, 68, 68, 0.8) !important;
  border: 1px solid rgba(220, 38, 38, 0.6);
}

/* 状态指示器样式 */
.status-indicator {
  font-size: 7px;
  padding: 1px 4px;
  border-radius: 3px;
  font-weight: 500;
  text-shadow: none;
  line-height: 1.1;
}

.status-indicator.offline {
  background-color: rgba(220, 38, 38, 0.9);
  color: #ffffff;
  border: 1px solid rgba(185, 28, 28, 0.8);
  animation: pulse-red 2s infinite;
}

.status-indicator.online {
  background-color: rgba(34, 197, 94, 0.9);
  color: #ffffff;
  border: 1px solid rgba(21, 128, 61, 0.8);
  animation: pulse-green 2s infinite;
}


/* 状态指示器动画 */
@keyframes pulse-red {
  0%, 100% { 
    box-shadow: 0 0 0 0 rgba(220, 38, 38, 0.7); 
  }
  50% { 
    box-shadow: 0 0 0 4px rgba(220, 38, 38, 0); 
  }
}

@keyframes pulse-green {
  0%, 100% { 
    box-shadow: 0 0 0 0 rgba(34, 197, 94, 0.7); 
  }
  50% { 
    box-shadow: 0 0 0 4px rgba(34, 197, 94, 0); 
  }
}

.placeholder, .scroll-placeholder {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  color: #fff;
  background-color: #333;
}

.scroll-placeholder {
  position: relative;
  background-color: #222;
}

/* 观众区域空状态简单样式 */
.audience-empty-simple {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100%;
  min-height: 200px;
}

.empty-text {
  color: rgba(255, 255, 255, 0.6);
  font-size: 16px;
  text-align: center;
}

.audience-placeholder {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  width: 100%;
  height: 100%;
  background: linear-gradient(135deg, #374151 0%, #4b5563 50%, #374151 100%);
  border-radius: 12px;
  color: #d1d5db;
  border: 2px solid rgba(107, 114, 128, 0.3);
  transition: all 0.3s ease;
}

/* 未加入直播的占位符样式 */
.audience-placeholder.not-joined {
  background: linear-gradient(135deg, #7f1d1d 0%, #991b1b 50%, #7f1d1d 100%);
  border: 2px solid rgba(220, 38, 38, 0.5);
  color: #fecaca;
}

.audience-placeholder.not-joined .placeholder-icon {
  opacity: 0.8;
  filter: brightness(1.2);
}

.not-joined-text {
  font-size: 22rpx;
  color: #fca5a5;
  margin-top: 8rpx;
  font-weight: 600;
  text-align: center;
}

.placeholder-icon {
  font-size: 60rpx;
  margin-bottom: 12rpx;
  opacity: 0.7;
}

.placeholder-text {
  font-size: 28rpx;
  color: #d1d5db;
  text-align: center;
  font-weight: 500;
}

/* 弹幕历史列表样式 */
.danmaku-history-item {
  display: flex;
  align-items: center;
  padding: 1rpx 0;
  border-left: 2rpx solid #ffffff;
  margin-bottom: 1rpx;
  padding-left: 4rpx;
}

.danmaku-history-user {
  color: #007AFF;
  font-weight: bold;
  margin-right: 4rpx;
  font-size: 10px;
  white-space: nowrap;
}

.danmaku-history-content {
  flex: 1;
  color: #ffffff;
  font-size: 10px;
  margin-right: 4rpx;
  word-break: break-all;
  line-height: 1.1;
}

.danmaku-history-time {
  color: #999;
  font-size: 8rpx;
  white-space: nowrap;
}

.danmaku-placeholder {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 200rpx;
  color: #666;
  font-size: 24rpx;
}

/* 控制按钮样式 */
.controls {
  display: flex;
  justify-content: space-around;
  margin-bottom: 30px;
  gap: 20px;
  padding: 25px 40px;
  background: rgba(255, 255, 255, 0.05);
  border-radius: 20px;
  backdrop-filter: blur(10px);
  border: 1px solid rgba(255, 255, 255, 0.1);
  width: 100%;
  box-sizing: border-box;
}

.control-btn {
  flex: 1;
  height: 50px;
  font-size: 14px;
  border-radius: 25px;
  border: none;
  color: white;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  position: relative;
  overflow: hidden;
  backdrop-filter: blur(10px);
  border: 1px solid rgba(255, 255, 255, 0.2);
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
  box-shadow: 
    0 4px 15px rgba(0, 0, 0, 0.2),
    inset 0 1px 0 rgba(255, 255, 255, 0.2);
}

.control-btn::before {
  content: '';
  position: absolute;
  top: 0;
  left: -100%;
  width: 100%;
  height: 100%;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
  transition: left 0.5s;
}

.control-btn:hover::before {
  left: 100%;
}

.control-btn:hover {
  transform: translateY(-2px) scale(1.05);
  box-shadow: 
    0 8px 25px rgba(0, 0, 0, 0.3),
    inset 0 1px 0 rgba(255, 255, 255, 0.3);
}

.control-btn:active {
  transform: translateY(0) scale(0.98);
}

.start-btn {
  background: linear-gradient(135deg, #3b82f6, #1d4ed8);
}

.start-btn:hover {
  background: linear-gradient(135deg, #2563eb, #1e40af);
  box-shadow: 0 8px 25px rgba(59, 130, 246, 0.4);
}

.stop-btn {
  background: linear-gradient(135deg, #ef4444, #dc2626);
}

.stop-btn:hover {
  background: linear-gradient(135deg, #dc2626, #b91c1c);
  box-shadow: 0 8px 25px rgba(239, 68, 68, 0.4);
}

.publish-btn {
  background: linear-gradient(135deg, #22c55e, #16a34a);
}

.publish-btn:hover {
  background: linear-gradient(135deg, #16a34a, #15803d);
  box-shadow: 0 8px 25px rgba(34, 197, 94, 0.4);
}

.stop-publish-btn {
  background: linear-gradient(135deg, #f97316, #ea580c);
}

.stop-publish-btn:hover {
  background: linear-gradient(135deg, #ea580c, #c2410c);
  box-shadow: 0 8px 25px rgba(249, 115, 22, 0.4);
}

.switch-btn {
  background: linear-gradient(135deg, #a855f7, #9333ea);
}

.switch-btn:hover {
  background: linear-gradient(135deg, #9333ea, #7c3aed);
  box-shadow: 0 8px 25px rgba(168, 85, 247, 0.4);
}

.test-btn {
  background: linear-gradient(135deg, #10b981, #059669);
}

.test-btn:hover {
  background: linear-gradient(135deg, #059669, #047857);
  box-shadow: 0 8px 25px rgba(16, 185, 129, 0.4);
}

.attendance-btn {
  background: linear-gradient(135deg, #22c55e, #16a34a);
}

.attendance-btn:hover {
  background: linear-gradient(135deg, #16a34a, #15803d);
  box-shadow: 0 8px 25px rgba(34, 197, 94, 0.4);
}

.attendance-btn:disabled {
  background: linear-gradient(135deg, #6b7280, #4b5563);
  color: #9ca3af;
  cursor: not-allowed;
  transform: none;
  box-shadow: none;
}

.attendance-btn:disabled:hover {
  transform: none;
  box-shadow: none;
}

.monitoring-btn {
  background: linear-gradient(135deg, #f59e0b, #d97706);
}

.monitoring-btn:hover {
  background: linear-gradient(135deg, #d97706, #b45309);
  box-shadow: 0 8px 25px rgba(245, 158, 11, 0.4);
}

.monitoring-btn.active {
  background: linear-gradient(135deg, #10b981, #059669);
  box-shadow: 0 6px 20px rgba(16, 185, 129, 0.3);
}

.monitoring-btn.active:hover {
  background: linear-gradient(135deg, #059669, #047857);
  box-shadow: 0 8px 25px rgba(16, 185, 129, 0.4);
}

/* 弹幕发送区域样式 */
.danmaku-input-section {
  padding: 25px 40px;
  background: linear-gradient(135deg, rgba(59, 130, 246, 0.1), rgba(147, 51, 234, 0.1));
  border-top: 2px solid rgba(59, 130, 246, 0.2);
  border-radius: 20px 20px 0 0;
  backdrop-filter: blur(10px);
  width: 100%;
  box-sizing: border-box;
}

.danmaku-input-section .input-area {
  display: flex;
  align-items: center;
  gap: 20rpx;
}

.danmaku-switch {
  display: flex;
  align-items: center;
  gap: 10rpx;
}

.switch-text {
  color: #ffffff;
  font-size: 28rpx;
}

.switch-icon {
  width: 40rpx;
  height: 20rpx;
  background-color: #666;
  border-radius: 10rpx;
  position: relative;
  transition: background-color 0.3s;
}

.switch-icon.active {
  background-color: #007aff;
}

.switch-icon::after {
  content: '';
  position: absolute;
  top: 2rpx;
  left: 2rpx;
  width: 16rpx;
  height: 16rpx;
  background-color: #ffffff;
  border-radius: 50%;
  transition: transform 0.3s;
}

.switch-icon.active::after {
  transform: translateX(20rpx);
}

.danmaku-input-section .message-input {
  flex: 1;
  height: 45px;
  background: rgba(255, 255, 255, 0.1);
  border-radius: 25px;
  padding: 0 20px;
  color: #ffffff;
  font-size: 14px;
  border: 1px solid rgba(255, 255, 255, 0.2);
  backdrop-filter: blur(5px);
  transition: all 0.3s ease;
}

.danmaku-input-section .message-input:focus {
  outline: none;
  border-color: rgba(59, 130, 246, 0.5);
  box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
  background: rgba(255, 255, 255, 0.15);
}

.danmaku-input-section .message-input::placeholder {
  color: #999;
}

.danmaku-input-section .send-btn {
  height: 45px;
  padding: 0 25px;
  background: linear-gradient(135deg, #3b82f6, #1d4ed8);
  color: white;
  border: 1px solid rgba(255, 255, 255, 0.2);
  border-radius: 25px;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.3s ease;
  backdrop-filter: blur(5px);
  box-shadow: 0 4px 15px rgba(59, 130, 246, 0.3);
}

.danmaku-input-section .send-btn:hover {
  background: linear-gradient(135deg, #2563eb, #1e40af);
  transform: translateY(-1px);
  box-shadow: 0 6px 20px rgba(59, 130, 246, 0.4);
}

.danmaku-input-section .send-btn:active {
  transform: translateY(0);
}

/* 全屏时的弹幕输入区域 */
.danmaku-input-section.fullscreen-input {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  z-index: 1001;
  background-color: rgba(42, 42, 42, 0.95);
  backdrop-filter: blur(10px);
  padding: 20rpx;
  border-top: 1rpx solid rgba(255, 255, 255, 0.2);
}

/* 全屏时确保输入框可见 */
.danmaku-input-section.fullscreen-input .input-area {
  max-width: 800rpx;
  margin: 0 auto;
}

.danmaku-input-section.fullscreen-input .message-input {
  background-color: rgba(58, 58, 58, 0.9);
  border: 1rpx solid rgba(255, 255, 255, 0.3);
}

.danmaku-input-section.fullscreen-input .send-btn {
  background-color: #007aff;
  border: 1rpx solid rgba(255, 255, 255, 0.2);
}

/* 全屏弹幕输入区域 */
.fullscreen-danmaku-input {
  position: fixed;
  top:94%;
  left: 50%;
  transform: translateX(-50%);
  z-index: 1004;
  background-color: rgba(0, 0, 0, 0.85);
  border-radius: 50rpx;
  padding: 15rpx 25rpx;
  backdrop-filter: blur(15px);
  border: 2rpx solid rgba(255, 255, 255, 0.3);
  box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.5);
  pointer-events: auto;
}

.fullscreen-input-area {
  display: flex;
  align-items: center;
  gap: 15rpx;
}

.fullscreen-message-input {
  width: 450rpx;
  height: 70rpx;
  background-color: rgba(255, 255, 255, 0.15);
  border: 2rpx solid rgba(255, 255, 255, 0.4);
  border-radius: 35rpx;
  padding: 0 25rpx;
  color: #ffffff;
  font-size: 30rpx;
  transition: all 0.3s ease;
}

.fullscreen-message-input:focus {
  border-color: #007aff;
  background-color: rgba(255, 255, 255, 0.2);
  outline: none;
}

.fullscreen-message-input::placeholder {
  color: rgba(255, 255, 255, 0.7);
  font-size: 28rpx;
}

.fullscreen-send-btn {
  height: 70rpx;
  padding: 0 35rpx;
  background-color: #007aff;
  color: white;
  border: 2rpx solid #007aff;
  border-radius: 35rpx;
  font-size: 30rpx;
  font-weight: bold;
  min-width: 120rpx;
  cursor: pointer;
  transition: all 0.3s ease;
}

.fullscreen-send-btn:hover {
  background-color: #0056b3;
  border-color: #0056b3;
  transform: scale(1.05);
}

.fullscreen-send-btn:active {
  transform: scale(0.95);
}

.danmaku-toggle-btn {
  height: 60rpx;
  padding: 0 20rpx;
  background-color: rgba(255, 255, 255, 0.2);
  color: white;
  border: 2rpx solid rgba(255, 255, 255, 0.4);
  border-radius: 30rpx;
  font-size: 24rpx;
  font-weight: bold;
  cursor: pointer;
  transition: all 0.3s ease;
}

.danmaku-toggle-btn.active {
  background-color: #007aff;
  border-color: #007aff;
}

/* 全屏控制按钮 */
.fullscreen-controls {
  position: absolute;
  top: 10rpx;
  right: 10rpx;
  z-index: 1003;
}

.fullscreen-btn {
  background-color: rgba(0, 0, 0, 0.7);
  color: white;
  border: 2rpx solid rgba(255, 255, 255, 0.5);
  border-radius: 8rpx;
  padding: 15rpx 25rpx;
  font-size: 28rpx;
  font-weight: bold;
  backdrop-filter: blur(10px);
  cursor: pointer;
  transition: all 0.3s ease;
  min-width: 120rpx;
  text-align: center;
}

.fullscreen-btn:hover {
  background-color: rgba(0, 0, 0, 0.9);
  border-color: rgba(255, 255, 255, 0.8);
  transform: scale(1.05);
}

.fullscreen-btn:active {
  transform: scale(0.95);
}

/* 弹幕滚动样式 - 显示在主画面区域 */
.danmaku-container {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  pointer-events: none;
  overflow: hidden;
  z-index: 50;
}

/* 全屏时的弹幕容器 */
.danmaku-container.fullscreen-danmaku {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  width: 100vw;
  height: 100vh;
  z-index: 1000;
}

.danmaku-scroll-item {
  position: absolute;
  white-space: nowrap;
  text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5);
  animation: danmaku 8s linear;
  animation-fill-mode: forwards;
  z-index: 100;
  pointer-events: none;
  color: #ffffff;
  font-size: 16px;
  font-weight: bold;
}

/* 弹幕滚动动画 */
@keyframes danmaku {
  0% {
    transform: translateX(100vw);
    opacity: 0;
  }
  5% {
    opacity: 1;
  }
  95% {
    opacity: 1;
  }
  100% {
    transform: translateX(-100vw);
    opacity: 0;
    visibility: hidden;
  }
}

.status-info {
  text-align: center;
  padding: 20rpx 0;
  color: #666;
  font-size: 28rpx;
  background-color: #2a2a2a;
}

.users-info {
  padding: 10rpx 20rpx;
  background-color: #f5f5f5;
  border-radius: 5rpx;
  margin: 10rpx 20rpx;
}

.user-list {
  display: flex;
  flex-wrap: wrap;
  margin-top: 5rpx;
}

.user-item {
  background-color: #e0e0e0;
  padding: 5rpx 10rpx;
  margin: 2rpx;
  border-radius: 3rpx;
  font-size: 20rpx;
}

.publish-info {
  padding: 20rpx 40px;
  text-align: center;
  width: 100%;
  box-sizing: border-box;
}

.publish-input {
  width: 100%;
  padding: 10rpx;
  border: 1px solid #ccc;
  border-radius: 5rpx;
  box-sizing: border-box;
}

/* 观众视频网格响应式布局 - 适配30个学生，优化空间利用，适应更大的卡片尺寸 */
@media (min-width: 2400px) {
  .audience-video-wrapper {
    grid-template-columns: repeat(8, 1fr);
  }
}

@media (min-width: 2000px) and (max-width: 2399px) {
  .audience-video-wrapper {
    grid-template-columns: repeat(7, 1fr);
  }
}

@media (min-width: 1600px) and (max-width: 1999px) {
  .audience-video-wrapper {
    grid-template-columns: repeat(6, 1fr);
  }
}

@media (min-width: 1400px) and (max-width: 1599px) {
  .audience-video-wrapper {
    grid-template-columns: repeat(5, 1fr);
  }
}

@media (min-width: 1200px) and (max-width: 1399px) {
  .audience-video-wrapper {
    grid-template-columns: repeat(4, 1fr);
  }
}

@media (min-width: 1000px) and (max-width: 1199px) {
  .audience-video-wrapper {
    grid-template-columns: repeat(4, 1fr);
  }
}

@media (min-width: 800px) and (max-width: 999px) {
  .audience-video-wrapper {
    grid-template-columns: repeat(3, 1fr);
  }
}

@media (min-width: 600px) and (max-width: 799px) {
  .audience-video-wrapper {
    grid-template-columns: repeat(3, 1fr);
  }
}

@media (max-width: 599px) {
  .audience-video-wrapper {
    grid-template-columns: repeat(2, 1fr);
  }
}

/* 响应式设计 */
@media (max-width: 1200px) {
  .main-content {
    flex-direction: column;
    gap: 10px;
  }
  
  .main-video-section {
    flex: none;
    height: 40vh;
  }
  
  .audience-video-section {
    flex: none;
    height: 45vh;
  }
  
  .danmaku-list-section {
    flex: 1;
    height: 15vh;
  }
}

@media (max-width: 768px) {
  .controls {
    flex-direction: column;
    gap: 10px;
  }
  
  .control-btn {
    height: 45px;
    font-size: 12px;
  }
  
  .main-content {
    padding: 10px;
  }
  
  .header {
    padding: 15px 0;
  }
  
  .title {
    font-size: 16px;
  }
}

/* 全局滚动条样式 */
.container * {
  scrollbar-width: thin;
  scrollbar-color: rgba(59, 130, 246, 0.5) rgba(255, 255, 255, 0.1);
}

.container *::-webkit-scrollbar {
  width: 6px;
  height: 6px;
}

.container *::-webkit-scrollbar-track {
  background: rgba(255, 255, 255, 0.1);
  border-radius: 3px;
}

.container *::-webkit-scrollbar-thumb {
  background: linear-gradient(135deg, #3b82f6, #1d4ed8);
  border-radius: 3px;
}

.container *::-webkit-scrollbar-thumb:hover {
  background: linear-gradient(135deg, #2563eb, #1e40af);
}

/* 淡入动画 */
@keyframes fadeIn {
  from {
    opacity: 0;
    transform: translateY(20px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.main-video-section,
.audience-video-section,
.danmaku-list-section {
  animation: fadeIn 0.6s ease-out;
}

.main-video-section {
  animation-delay: 0.1s;
}

.audience-video-section {
  animation-delay: 0.2s;
}

.danmaku-list-section {
  animation-delay: 0.3s;
}

/* 全屏预览按钮样式优化 */
.fullscreen-preview-btn {
  background: linear-gradient(135deg, rgba(59, 130, 246, 0.8), rgba(147, 51, 234, 0.8));
  border: 1px solid rgba(255, 255, 255, 0.2);
  border-radius: 8px;
  padding: 8px 16px;
  color: white;
  font-size: 12px;
  font-weight: 500;
  cursor: pointer;
  transition: all 0.3s ease;
  backdrop-filter: blur(10px);
  box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
}

.fullscreen-preview-btn:hover {
  background: linear-gradient(135deg, rgba(37, 99, 235, 0.9), rgba(126, 34, 206, 0.9));
  transform: translateY(-1px);
  box-shadow: 0 6px 20px rgba(59, 130, 246, 0.4);
}

</style>